Validation for entity's additionalInfo

This commit is contained in:
ViacheslavKlimov 2022-11-17 15:33:12 +02:00
parent 6a75cd076f
commit e7995fb02c
3 changed files with 35 additions and 17 deletions

View File

@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.validation.NoXss;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -36,6 +37,7 @@ import java.util.function.Consumer;
public abstract class SearchTextBasedWithAdditionalInfo<I extends UUIDBased> extends SearchTextBased<I> implements HasAdditionalInfo {
public static final ObjectMapper mapper = new ObjectMapper();
@NoXss
private transient JsonNode additionalInfo;
@JsonIgnore
private byte[] additionalInfoBytes;

View File

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.service;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.Policy;
@ -48,12 +49,18 @@ public class NoXssValidator implements ConstraintValidator<NoXss, Object> {
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
if (!(value instanceof String) || ((String) value).isEmpty()) {
String stringValue;
if (value instanceof CharSequence || value instanceof JsonNode) {
stringValue = value.toString();
} else {
return true;
}
if (stringValue.isEmpty()) {
return true;
}
try {
return xssChecker.scan((String) value, xssPolicy).getNumberOfErrors() == 0;
return xssChecker.scan(stringValue, xssPolicy).getNumberOfErrors() == 0;
} catch (ScanException | PolicyException e) {
return false;
}

View File

@ -15,23 +15,16 @@
*/
package org.thingsboard.server.dao.service;
import org.junit.jupiter.api.BeforeAll;
import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.asset.Asset;
import javax.validation.ConstraintValidatorContext;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class NoXssValidatorTest {
private static NoXssValidator validator;
@BeforeAll
public static void beforeAll() {
validator = new NoXssValidator();
validator.initialize(null);
}
@ParameterizedTest
@ValueSource(strings = {
@ -44,9 +37,25 @@ public class NoXssValidatorTest {
" <img src= \"http://site.com/\" > ",
"123 <input type=text value=a onfocus=alert(1337) AUTOFOCUS>bebe"
})
public void testIsNotValid(String stringWithXss) {
boolean isValid = validator.isValid(stringWithXss, mock(ConstraintValidatorContext.class));
assertFalse(isValid);
public void givenEntityWithMaliciousPropertyValue_thenReturnValidationError(String maliciousString) {
Asset invalidAsset = new Asset();
invalidAsset.setName(maliciousString);
assertThatThrownBy(() -> {
ConstraintValidator.validateFields(invalidAsset);
}).hasMessageContaining("field value is malformed");
}
@Test
public void givenEntityWithMaliciousValueInAdditionalInfo_thenReturnValidationError() {
Asset invalidAsset = new Asset();
String maliciousValue = "qwerty<script>alert(document.cookie)</script>qwerty";
invalidAsset.setAdditionalInfo(JacksonUtil.newObjectNode()
.set("description", new TextNode(maliciousValue)));
assertThatThrownBy(() -> {
ConstraintValidator.validateFields(invalidAsset);
}).hasMessageContaining("field value is malformed");
}
}