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

View File

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

View File

@ -15,23 +15,16 @@
*/ */
package org.thingsboard.server.dao.service; 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.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; 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.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;
public class NoXssValidatorTest { public class NoXssValidatorTest {
private static NoXssValidator validator;
@BeforeAll
public static void beforeAll() {
validator = new NoXssValidator();
validator.initialize(null);
}
@ParameterizedTest @ParameterizedTest
@ValueSource(strings = { @ValueSource(strings = {
@ -44,9 +37,25 @@ public class NoXssValidatorTest {
" <img src= \"http://site.com/\" > ", " <img src= \"http://site.com/\" > ",
"123 <input type=text value=a onfocus=alert(1337) AUTOFOCUS>bebe" "123 <input type=text value=a onfocus=alert(1337) AUTOFOCUS>bebe"
}) })
public void testIsNotValid(String stringWithXss) { public void givenEntityWithMaliciousPropertyValue_thenReturnValidationError(String maliciousString) {
boolean isValid = validator.isValid(stringWithXss, mock(ConstraintValidatorContext.class)); Asset invalidAsset = new Asset();
assertFalse(isValid); 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");
} }
} }