revert tskv value noxss validation
This commit is contained in:
		
							parent
							
								
									631c529b97
								
							
						
					
					
						commit
						08efbd1c85
					
				@ -259,13 +259,11 @@ sql:
 | 
			
		||||
    batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}"
 | 
			
		||||
    stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}"
 | 
			
		||||
    batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
 | 
			
		||||
    noxss_validation_enabled: "${SQL_ATTRIBUTES_NOXSS_VALIDATION_ENABLED:true}"
 | 
			
		||||
  ts:
 | 
			
		||||
    batch_size: "${SQL_TS_BATCH_SIZE:10000}"
 | 
			
		||||
    batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}"
 | 
			
		||||
    stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}"
 | 
			
		||||
    batch_threads: "${SQL_TS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
 | 
			
		||||
    noxss_validation_enabled: "${SQL_TS_NOXSS_VALIDATION_ENABLED:true}"
 | 
			
		||||
  ts_latest:
 | 
			
		||||
    batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}"
 | 
			
		||||
    batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}"
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.controller;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.stringtemplate.v4.ST;
 | 
			
		||||
import org.thingsboard.server.common.data.Device;
 | 
			
		||||
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
 | 
			
		||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
 | 
			
		||||
@ -32,10 +33,7 @@ public abstract class BaseTelemetryControllerTest extends AbstractControllerTest
 | 
			
		||||
        String correctRequestBody = "{\"data\": \"value\"}";
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", correctRequestBody, String.class, status().isOk());
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", correctRequestBody, String.class, status().isOk());
 | 
			
		||||
        String invalidRequestBody = "{\"data\": \"<object data=\\\"data:text/html,<script>alert(document)</script>\\\"></object>\"}";
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", invalidRequestBody, String.class, status().isBadRequest());
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest());
 | 
			
		||||
        invalidRequestBody = "{\"<object data=\\\"data:text/html,<script>alert(document)</script>\\\"></object>\": \"data\"}";
 | 
			
		||||
        String invalidRequestBody = "{\"<object data=\\\"data:text/html,<script>alert(document)</script>\\\"></object>\": \"data\"}";
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", invalidRequestBody, String.class, status().isBadRequest());
 | 
			
		||||
        doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -15,14 +15,11 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.common.data.kv;
 | 
			
		||||
 | 
			
		||||
import org.thingsboard.server.common.data.validation.NoXss;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public class JsonDataEntry extends BasicKvEntry {
 | 
			
		||||
 | 
			
		||||
    @NoXss
 | 
			
		||||
    private final String value;
 | 
			
		||||
 | 
			
		||||
    public JsonDataEntry(String key, String value) {
 | 
			
		||||
 | 
			
		||||
@ -15,8 +15,6 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.common.data.kv;
 | 
			
		||||
 | 
			
		||||
import org.thingsboard.server.common.data.validation.NoXss;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +22,6 @@ public class StringDataEntry extends BasicKvEntry {
 | 
			
		||||
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    @NoXss
 | 
			
		||||
    private final String value;
 | 
			
		||||
 | 
			
		||||
    public StringDataEntry(String key, String value) {
 | 
			
		||||
@ -68,7 +65,7 @@ public class StringDataEntry extends BasicKvEntry {
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "StringDataEntry{" + "value='" + value + '\'' + "} " + super.toString();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getValueAsString() {
 | 
			
		||||
        return value;
 | 
			
		||||
 | 
			
		||||
@ -30,12 +30,12 @@ public class AttributeUtils {
 | 
			
		||||
        Validator.validateString(scope, "Incorrect scope " + scope);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void validate(List<AttributeKvEntry> kvEntries, boolean validateNoxss) {
 | 
			
		||||
        kvEntries.forEach(kv -> validate(kv, validateNoxss));
 | 
			
		||||
    public static void validate(List<AttributeKvEntry> kvEntries) {
 | 
			
		||||
        kvEntries.forEach(AttributeUtils::validate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void validate(AttributeKvEntry kvEntry, boolean validateNoxss) {
 | 
			
		||||
        KvUtils.validate(kvEntry, validateNoxss);
 | 
			
		||||
    public static void validate(AttributeKvEntry kvEntry) {
 | 
			
		||||
        KvUtils.validate(kvEntry);
 | 
			
		||||
        if (kvEntry.getDataType() == null) {
 | 
			
		||||
            throw new IncorrectParameterException("Incorrect kvEntry. Data type can't be null");
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
@ -46,9 +46,6 @@ import static org.thingsboard.server.dao.attributes.AttributeUtils.validate;
 | 
			
		||||
public class BaseAttributesService implements AttributesService {
 | 
			
		||||
    private final AttributesDao attributesDao;
 | 
			
		||||
 | 
			
		||||
    @Value("${sql.attributes.noxss_validation_enabled:true}")
 | 
			
		||||
    private boolean noxssValidationEnabled;
 | 
			
		||||
 | 
			
		||||
    public BaseAttributesService(AttributesDao attributesDao) {
 | 
			
		||||
        this.attributesDao = attributesDao;
 | 
			
		||||
    }
 | 
			
		||||
@ -86,14 +83,14 @@ public class BaseAttributesService implements AttributesService {
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<String> save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) {
 | 
			
		||||
        validate(entityId, scope);
 | 
			
		||||
        AttributeUtils.validate(attribute, noxssValidationEnabled);
 | 
			
		||||
        AttributeUtils.validate(attribute);
 | 
			
		||||
        return attributesDao.save(tenantId, entityId, scope, attribute);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<List<String>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
 | 
			
		||||
        validate(entityId, scope);
 | 
			
		||||
        AttributeUtils.validate(attributes, noxssValidationEnabled);
 | 
			
		||||
        AttributeUtils.validate(attributes);
 | 
			
		||||
        List<ListenableFuture<String>> saveFutures = attributes.stream().map(attribute -> attributesDao.save(tenantId, entityId, scope, attribute)).collect(Collectors.toList());
 | 
			
		||||
        return Futures.allAsList(saveFutures);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -70,9 +70,6 @@ public class CachedAttributesService implements AttributesService {
 | 
			
		||||
    @Value("${cache.type:caffeine}")
 | 
			
		||||
    private String cacheType;
 | 
			
		||||
 | 
			
		||||
    @Value("${sql.attributes.noxss_validation_enabled:true}")
 | 
			
		||||
    private boolean noxssValidationEnabled;
 | 
			
		||||
 | 
			
		||||
    public CachedAttributesService(AttributesDao attributesDao,
 | 
			
		||||
                                   StatsFactory statsFactory,
 | 
			
		||||
                                   CacheExecutorService cacheExecutorService,
 | 
			
		||||
@ -215,7 +212,7 @@ public class CachedAttributesService implements AttributesService {
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<String> save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) {
 | 
			
		||||
        validate(entityId, scope);
 | 
			
		||||
        AttributeUtils.validate(attribute, noxssValidationEnabled);
 | 
			
		||||
        AttributeUtils.validate(attribute);
 | 
			
		||||
        ListenableFuture<String> future = attributesDao.save(tenantId, entityId, scope, attribute);
 | 
			
		||||
        return Futures.transform(future, key -> evict(entityId, scope, attribute, key), cacheExecutor);
 | 
			
		||||
    }
 | 
			
		||||
@ -223,7 +220,7 @@ public class CachedAttributesService implements AttributesService {
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<List<String>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
 | 
			
		||||
        validate(entityId, scope);
 | 
			
		||||
        AttributeUtils.validate(attributes, noxssValidationEnabled);
 | 
			
		||||
        AttributeUtils.validate(attributes);
 | 
			
		||||
 | 
			
		||||
        List<ListenableFuture<String>> futures = new ArrayList<>(attributes.size());
 | 
			
		||||
        for (var attribute : attributes) {
 | 
			
		||||
 | 
			
		||||
@ -81,9 +81,6 @@ public class BaseTimeseriesService implements TimeseriesService {
 | 
			
		||||
    @Value("${database.ts_max_intervals}")
 | 
			
		||||
    private long maxTsIntervals;
 | 
			
		||||
 | 
			
		||||
    @Value("${sql.ts.noxss_validation_enabled:true}")
 | 
			
		||||
    private boolean noxssValidationEnabled;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TimeseriesDao timeseriesDao;
 | 
			
		||||
 | 
			
		||||
@ -159,7 +156,7 @@ public class BaseTimeseriesService implements TimeseriesService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
 | 
			
		||||
        KvUtils.validate(tsKvEntry, noxssValidationEnabled);
 | 
			
		||||
        KvUtils.validate(tsKvEntry);
 | 
			
		||||
        validate(entityId);
 | 
			
		||||
        List<ListenableFuture<Integer>> futures = Lists.newArrayListWithExpectedSize(INSERTS_PER_ENTRY);
 | 
			
		||||
        saveAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, 0L);
 | 
			
		||||
@ -177,7 +174,7 @@ public class BaseTimeseriesService implements TimeseriesService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Integer> doSave(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl, boolean saveLatest) {
 | 
			
		||||
        KvUtils.validate(tsKvEntries, noxssValidationEnabled);
 | 
			
		||||
        KvUtils.validate(tsKvEntries);
 | 
			
		||||
        int inserts = saveLatest ? INSERTS_PER_ENTRY : INSERTS_PER_ENTRY_WITHOUT_LATEST;
 | 
			
		||||
        List<ListenableFuture<Integer>> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size() * inserts);
 | 
			
		||||
        for (TsKvEntry tsKvEntry : tsKvEntries) {
 | 
			
		||||
@ -192,7 +189,7 @@ public class BaseTimeseriesService implements TimeseriesService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<List<Void>> saveLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries) {
 | 
			
		||||
        KvUtils.validate(tsKvEntries, noxssValidationEnabled);
 | 
			
		||||
        KvUtils.validate(tsKvEntries);
 | 
			
		||||
        List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size());
 | 
			
		||||
        for (TsKvEntry tsKvEntry : tsKvEntries) {
 | 
			
		||||
            futures.add(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry));
 | 
			
		||||
 | 
			
		||||
@ -22,16 +22,14 @@ import org.thingsboard.server.dao.service.ConstraintValidator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class KvUtils {
 | 
			
		||||
    public static void validate(List<? extends KvEntry> tsKvEntries, boolean validateNoxss) {
 | 
			
		||||
        tsKvEntries.forEach(kvEntry -> validate(kvEntry, validateNoxss));
 | 
			
		||||
    public static void validate(List<? extends KvEntry> tsKvEntries) {
 | 
			
		||||
        tsKvEntries.forEach(KvUtils::validate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void validate(KvEntry tsKvEntry, boolean validateNoxss) {
 | 
			
		||||
    public static void validate(KvEntry tsKvEntry) {
 | 
			
		||||
        if (tsKvEntry == null) {
 | 
			
		||||
            throw new IncorrectParameterException("Key value entry can't be null");
 | 
			
		||||
        }
 | 
			
		||||
        if (validateNoxss) {
 | 
			
		||||
            ConstraintValidator.validateFields(tsKvEntry);
 | 
			
		||||
        }
 | 
			
		||||
        ConstraintValidator.validateFields(tsKvEntry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@ package org.thingsboard.server.dao.service;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.jupiter.api.Assertions;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.JsonDataEntry;
 | 
			
		||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
 | 
			
		||||
@ -30,15 +29,9 @@ class ConstraintValidatorTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    void validateFields() {
 | 
			
		||||
        StringDataEntry stringDataEntryValid = new StringDataEntry("key", "value");
 | 
			
		||||
 | 
			
		||||
        StringDataEntry stringDataEntryInvalid1 = new StringDataEntry("<object type=\"text/html\"><script>alert(document)</script></object>", "value");
 | 
			
		||||
        StringDataEntry stringDataEntryInvalid2 = new StringDataEntry("key", "<object type=\"text/html\"><script>alert(document)</script></object>");
 | 
			
		||||
 | 
			
		||||
        JsonDataEntry jsonDataEntryInvalid = new JsonDataEntry("key", "{\"value\": <object type=\"text/html\"><script>alert(document)</script></object>}");
 | 
			
		||||
 | 
			
		||||
        Assert.assertThrows(DataValidationException.class, () -> ConstraintValidator.validateFields(stringDataEntryInvalid1));
 | 
			
		||||
        Assert.assertThrows(DataValidationException.class, () -> ConstraintValidator.validateFields(stringDataEntryInvalid2));
 | 
			
		||||
        Assert.assertThrows(DataValidationException.class, () -> ConstraintValidator.validateFields(jsonDataEntryInvalid));
 | 
			
		||||
        ConstraintValidator.validateFields(stringDataEntryValid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user