Skip to content

Commit

Permalink
Demo XSS vulnerability and cleanup (#16)
Browse files Browse the repository at this point in the history
* Create gradle.yml for Actions (#1) (#2)

* Create gradle.yml for Actions

* Update gradle.yml

* actions exectute denied

* Syncing (#4)

* Create gradle.yml for Actions (#1)

* Create gradle.yml for Actions

* Update gradle.yml

* actions exectute denied

* modify action build to publish built to packages (#3)

* Updating old dependencies (#10)

* Create gradle.yml for Actions (#1)

* Create gradle.yml for Actions

* Update gradle.yml

* actions exectute denied

* modify action build to publish built to packages (#3)

* Create dependabot.yml

* Bump org.junit:junit-bom from 5.9.1 to 5.10.1 (#8)

Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.1 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](junit-team/junit5@r5.9.1...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump org.apache.kafka:kafka-streams from 3.2.3 to 3.6.0 (#7)

Bumps org.apache.kafka:kafka-streams from 3.2.3 to 3.6.0.

---
updated-dependencies:
- dependency-name: org.apache.kafka:kafka-streams
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fragmenting html using thymeleaf, added dataTables with xlsx,pdf,csv export for consumer table, added errors rejected to return

* added errors rejected to return

* Updating dependabot deps, added xss purify demo, logback->log4j2, field injection->constructor injection

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
mibracy and dependabot[bot] authored Dec 8, 2023
1 parent 7887ba7 commit af5ea59
Show file tree
Hide file tree
Showing 15 changed files with 115 additions and 90 deletions.
26 changes: 18 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
plugins {
id "java"
id "war"
id "org.springframework.boot" version"2.7.17"
id("org.sonarqube") version "4.0.0.2929"
id("org.springframework.boot") version "2.7.17"
}

group = "org.example"
Expand All @@ -21,7 +22,7 @@ repositories {

dependencies {
implementation 'org.apache.avro:avro:1.11.3'
implementation 'org.apache.poi:poi-ooxml:5.2.4'
implementation 'org.apache.poi:poi-ooxml:5.2.5'
implementation 'org.apache.kafka:kafka-streams:3.6.0'
implementation 'org.springframework.kafka:spring-kafka:2.9.13'
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand All @@ -30,15 +31,15 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation "org.springframework.boot:spring-boot-starter-oauth2-client"
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
implementation 'org.springframework.security:spring-security-core:5.8.8'

implementation 'org.slf4j:slf4j-jdk14:2.0.9'
implementation 'com.h2database:h2:2.2.224'
implementation 'com.thoughtworks.xstream:xstream:1.4.20'
implementation 'net.datafaker:datafaker:1.9.0'

implementation 'org.webjars:webjars-locator:0.48'
implementation 'org.webjars:webjars-locator:0.50'
implementation 'org.webjars:bootstrap:5.3.2'
implementation 'org.webjars:datatables:1.13.5'
implementation 'org.webjars:datatables-buttons:2.4.1'
Expand All @@ -47,14 +48,23 @@ dependencies {
implementation 'org.webjars:sockjs-client:1.5.1'
implementation 'org.webjars:momentjs:2.29.4'
implementation 'org.webjars.npm:chart.js:4.4.0'
implementation 'org.webjars.npm:dompurify:3.0.6'
implementation 'org.webjars:jszip:3.10.1'
implementation 'org.webjars.bower:pdfmake:0.2.7'

annotationProcessor'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
compileOnly 'org.projectlombok:lombok:1.18.30'

testImplementation(platform("org.junit:junit-bom:5.10.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation platform('org.junit:junit-bom:5.10.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.assertj:assertj-core:3.24.2'
}

configurations {
configureEach {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}

tasks.test {
Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/example/Kafka.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

@SpringBootApplication
public class Kafka extends SpringBootServletInitializer {

public static void main(String[] args) {
SpringApplication.run(Kafka.class, args);
}
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/example/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import javax.servlet.http.HttpServletRequest;


@Configuration
public class SecurityConfig {

Expand Down Expand Up @@ -41,8 +40,10 @@ protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.and()
.headers(headers ->
headers.referrerPolicy(referrer ->
referrer.policy(NO_REFERRER_WHEN_DOWNGRADE)).frameOptions().sameOrigin())
.oauth2Login(withDefaults()); // comment out to secure DB completely from access
referrer.policy(NO_REFERRER_WHEN_DOWNGRADE))
.frameOptions().sameOrigin()
.xssProtection().block(true)
).oauth2Login(withDefaults()); // comment out to secure DB completely from access
return http.build();
}

Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/example/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/kafka");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setAllowedOriginPatterns("*").withSockJS();
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/org/example/controllers/KafkaController.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ public class KafkaController {

@Value("${bearer}")
private String TOKEN;
private final ProducerService producer;
private final EventRepository eventRepo;
private final SmartValidator validator;

@Autowired
private ProducerService producer;

@Autowired
private EventRepository eventRepo;

@Autowired
SmartValidator validator;
public KafkaController(EventRepository eventRepo, ProducerService producer,
SmartValidator validator) {
this.producer = producer;
this.eventRepo = eventRepo;
this.validator = validator;
}

@PostMapping("/api/send")
public ResponseEntity<String> sendToKafkaTopic(@RequestBody String event, HttpServletRequest request) {
Expand Down Expand Up @@ -119,8 +121,7 @@ public ResponseEntity<String> publishToKafkaTopic(@RequestParam("message") Strin
}

@GetMapping("/sql/topics")
@ResponseBody
public ResponseEntity<?> findTopics() {
public ResponseEntity<List<String>> findTopics() {
return new ResponseEntity<>(eventRepo.findDistinctTopic(), HttpStatus.OK);
}

Expand Down
28 changes: 14 additions & 14 deletions src/main/java/org/example/controllers/SQLController.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

Expand All @@ -31,18 +30,19 @@ public class SQLController {

@Value("${bearer}")
private String BEARER;
private final UserRepository userRepo;
private final SimpMessagingTemplate simp;
private final SmartValidator validator;
private final FileExportService exportService;

@Autowired
private UserRepository userRepo;

@Autowired
SimpMessagingTemplate simp;

@Autowired
SmartValidator validator;

@Autowired
FileExportService exportService;
public SQLController(UserRepository userRepo, SimpMessagingTemplate simp,
SmartValidator validator, FileExportService exportService) {
this.userRepo = userRepo;
this.simp = simp;
this.validator = validator;
this.exportService = exportService;
}

@PostMapping("/sql/test_users")
public ResponseEntity<String> testDBKafkaUsers(HttpServletRequest request) {
Expand All @@ -57,7 +57,7 @@ public ResponseEntity<String> testDBKafkaUsers(HttpServletRequest request) {

// mock Test users
List<H2User> users = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
for (int i = 0; i < 2; i++) {
Faker faker = new Faker();
String name = faker.futurama().character();
String email = faker.dungeonsAndDragons().monsters();
Expand All @@ -83,8 +83,8 @@ public ResponseEntity<String> testDBKafkaUsers(HttpServletRequest request) {
// userRepo.findAll().forEach(user -> logger.info(user.toString())); // dumps all to table to log

// dump entire DB to file in JSON and XML formats
Iterable<H2User> h2Repo = userRepo.findAll();
exportService.export("data/users", Collections.singleton(h2Repo), new ObjectDB(h2Repo));
ObjectDB h2Repo = new ObjectDB(userRepo.findAll());
exportService.export("data/users", h2Repo);

// send size of DB to Kafka Broker for real-time display
simp.convertAndSend("/topic/temperature", userRepo.count());
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/example/service/ConsumerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
@Slf4j
@Component
public class ConsumerService {
private final SimpMessagingTemplate template;

@Autowired
SimpMessagingTemplate template;
public ConsumerService(SimpMessagingTemplate template) {
this.template = template;
}

@KafkaListener(topics = "my-topic")
public void genericListen(String event) {
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/org/example/service/FileExportService.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ public class FileExportService {

@Value("${export.path:../temp/}")
private String exportPath;
private final List<String> types = Arrays.asList("json", "xml");
private final ProducerService producer;

@Autowired
private ProducerService producer;
public final List<String> types = Arrays.asList("json", "xml");
public FileExportService(ProducerService producer) {
this.producer = producer;
}

public void export(String name, Iterable<Object> data, ObjectDB odb) {
public void export(String name, ObjectDB odb) {
AtomicReference<String> converted = new AtomicReference<>("");

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
Expand All @@ -48,14 +51,14 @@ public void export(String name, Iterable<Object> data, ObjectDB odb) {
if ("json".equals(type)){
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
try {
converted.set(ow.writeValueAsString(data));
converted.set(ow.writeValueAsString(odb));
} catch (JsonProcessingException e) {
converted.set("");
log.error(String.valueOf(e));
}
} else if ("xml".equals(type)) {
try {
converted.set(convertObjectToxStreamXML(data, name.replace("data/","")));
converted.set(convertObjectToxStreamXML(odb, name.replace("data/","")));
} catch (UnsupportedEncodingException e) {
converted.set("");
log.error(String.valueOf(e));
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/example/service/ProducerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@

@Component
public class ProducerService {
private final KafkaTemplate<String, String> kafkaTemplate;

@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public ProducerService(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}

public ListenableFuture<SendResult<String, String>> sendEvent(KafkaPayload event) {
return kafkaTemplate.send(event.getTopic(), event.getKey() , event.getValue());
Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/example/sql/EventRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
@Repository
@Table(name = "EVENT")
public interface EventRepository extends CrudRepository<Event, Long> {

@Query("SELECT DISTINCT e.kafka_topic FROM Event e")
List<String> findDistinctTopic();

Expand Down
28 changes: 28 additions & 0 deletions src/main/resources/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="logPath">${sys:catalina.home}/logs</Property>
<Property name="rollingFileName">kafka</Property>
<Property name="pattern">%d [%-6p] %c{3} - %m%n</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${pattern}"/>
</Console>
<RollingFile name="rollingFile" fileName="${logPath}/${rollingFileName}.log" filePattern="${logPath}/archived/%d{yyyy-MM-dd}/${rollingFileName}_%i.log">
<PatternLayout pattern="${pattern}"/>
<Policies>
<!-- Causes a rollover if the log file is older than the current JVM's start time -->
<OnStartupTriggeringPolicy />
<!-- Causes a rollover once the date/time pattern no longer applies to the active file -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO" additivity="false">
<AppenderRef ref="console" />
<AppenderRef ref="rollingFile" />
</Root>
</Loggers>
</Configuration>
40 changes: 0 additions & 40 deletions src/main/resources/logback.xml

This file was deleted.

27 changes: 22 additions & 5 deletions src/main/resources/static/js/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ const config = {
}
}
};

let table;
const getCurrentTime = () => new Date()
.toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
.replaceAll(`,`,``);
/* Document Ready Event */
$(document).ready(function() {
const table = $('#kafkaTable').DataTable({
table = $('#kafkaTable').DataTable({
order: [[3, 'desc']],
dom: 'Blfrtip',
buttons: [
'copyHtml5',
Expand All @@ -73,8 +77,8 @@ $(document).ready(function() {

stompClient.subscribe('/topic/temperature', function(temperature) {
$('#temperature').text(temperature.body);
/* Push new data On X-Axis of Chart */
config.data.labels.push(new Date());
/* Push new date On X-Axis of Chart */
config.data.labels.push(getCurrentTime());
/* Push new data on Y-Axis of chart */
config.data.datasets.forEach(function(dataset) {
dataset.data.push(temperature.body);
Expand All @@ -84,12 +88,25 @@ $(document).ready(function() {

stompClient.subscribe('/topic/listen', function(payload) {
let data = JSON.parse(payload.body);
table.row.add([data["topic"], data["key"], data["value"], data["time"]]).draw();
const pureKey = DOMPurify.sanitize(data["key"]);
const pureValue = DOMPurify.sanitize(data["value"]);
table.row.add([data["topic"], pureKey, pureValue, data["time"]]).draw();
});
});

$("#inject").on('click', function () {
triggerMe();
});
});

function triggerMe() {
const dirty = '<img src=x onerror=prompt(`HelloWorld`)>';
table.row.add(['XSS dirty', dirty, 1, getCurrentTime()]).draw();

const cleaned = DOMPurify.sanitize(dirty);
table.row.add(['XSS clean', cleaned, 0, getCurrentTime()]).draw();
}

function getServerPath() {
return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
}
Loading

0 comments on commit af5ea59

Please sign in to comment.