├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── access-control-spring-security ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ ├── SecurityConfig.java │ │ │ └── contacts │ │ │ ├── Contact.java │ │ │ ├── ContactController.java │ │ │ └── ContactService.java │ └── resources │ │ ├── application.yml │ │ ├── data.sql │ │ ├── schema.sql │ │ └── templates │ │ ├── contacts │ │ ├── details.html │ │ └── list.html │ │ └── index.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── ApplicationTest.java ├── crypto-hash ├── pom.xml └── src │ ├── main │ └── java │ │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── hash │ │ ├── MD5.java │ │ ├── PBKDF2.java │ │ ├── PasswordComparator.java │ │ └── SHA512.java │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── hash │ ├── MD5Test.java │ ├── PBKDF2Test.java │ └── SHA512Test.java ├── crypto-java ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Keystore.java │ │ │ ├── asymmetric │ │ │ ├── DSA.java │ │ │ └── RSA.java │ │ │ └── symmetric │ │ │ └── AES.java │ └── resources │ │ └── samples.ks │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ ├── KeystoreTest.java │ ├── asymmetric │ ├── DSATest.java │ └── RSATest.java │ └── symmetric │ └── AESTest.java ├── crypto-shiro ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Keystore.java │ │ │ ├── hash │ │ │ └── SHA512.java │ │ │ └── symmetric │ │ │ └── AES.java │ └── resources │ │ └── samples.ks │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ ├── KeystoreTest.java │ ├── hash │ └── SHA512Test.java │ └── symmetric │ └── AESTest.java ├── crypto-tink ├── pom.xml └── src │ ├── main │ └── java │ │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── tink │ │ ├── aead │ │ ├── AesEaxWithGeneratedKey.java │ │ ├── AesGcmWithAwsKmsSavedKey.java │ │ └── AesGcmWithSavedKey.java │ │ ├── hybrid │ │ ├── EciesWithAwsKmsSavedKey.java │ │ ├── EciesWithGeneratedKey.java │ │ ├── EciesWithGeneratedKeyAndKeyRotation.java │ │ └── EciesWithSavedKey.java │ │ ├── mac │ │ ├── HmacShaWithGeneratedKey.java │ │ └── HmacShaWithSavedKey.java │ │ └── signature │ │ ├── EcdsaWithGeneratedKey.java │ │ └── EcdsaWithSavedKey.java │ └── test │ ├── java │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── tink │ │ ├── aead │ │ ├── AesEaxWithGeneratedKeyTest.java │ │ ├── AesGcmWithAwsKmsSavedKeyTest.java │ │ └── AesGcmWithSavedKeyTest.java │ │ ├── hybrid │ │ ├── EciesWithAwsKmsSavedKeyTest.java │ │ ├── EciesWithGeneratedKeyAndKeyRotationTest.java │ │ ├── EciesWithGeneratedKeyTest.java │ │ └── EciesWithSavedKeyTest.java │ │ ├── mac │ │ ├── HmacShaWithGeneratedKeyTest.java │ │ └── HmacShaWithSavedKeyTest.java │ │ └── signature │ │ ├── EcdsaWithGeneratedKeyTest.java │ │ └── EcdsaWithSavedKeyTest.java │ └── resources │ └── keysets │ ├── aead-aes-gcm-kms.json │ ├── aead-aes-gcm.json │ ├── hmac-sha.json │ ├── hybrid-ecies-kms-private.json │ ├── hybrid-ecies-kms-public.json │ ├── hybrid-ecies-private.json │ ├── hybrid-ecies-public.json │ ├── signature-ecdsa-private.json │ └── signature-ecdsa-public.json ├── csp-spring-security ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ ├── SecurityConfig.java │ │ │ └── greetings │ │ │ ├── Greeting.java │ │ │ └── GreetingController.java │ └── resources │ │ └── templates │ │ ├── index.html │ │ └── result.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── ApplicationTest.java ├── csrf-spring-security ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ ├── SecurityConfig.java │ │ │ ├── home │ │ │ └── IndexController.java │ │ │ └── orders │ │ │ ├── Order.java │ │ │ └── OrderController.java │ └── resources │ │ └── templates │ │ ├── index.html │ │ └── result.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ ├── ApplicationTest.java │ ├── home │ └── IndexControllerTest.java │ └── orders │ └── OrderControllerTest.java ├── csrf ├── pom.xml └── src │ └── main │ ├── java │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── csrf │ │ ├── CSRFTokenHandler.java │ │ └── OrderServlet.java │ └── webapp │ ├── WEB-INF │ └── web.xml │ ├── index.jsp │ └── resources │ └── css │ └── styles.css ├── direct-object-references ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ └── downloads │ │ │ ├── DownloadController.java │ │ │ └── DownloadService.java │ └── resources │ │ ├── ESAPI.properties │ │ ├── static │ │ └── files │ │ │ ├── cover.jpg │ │ │ └── cover.pdf │ │ └── templates │ │ └── index.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── ApplicationTest.java ├── intercept-me ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ └── tasks │ │ │ ├── FirstTask.java │ │ │ └── InterceptMeController.java │ └── resources │ │ └── templates │ │ ├── index.html │ │ └── result.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ ├── ApplicationTest.java │ └── tasks │ └── InterceptMeControllerTest.java ├── pom.xml ├── security-header ├── certificates │ └── keystore.jks ├── pom.xml └── src │ └── main │ ├── java │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── header │ │ ├── filter │ │ ├── CSP2Filter.java │ │ ├── CSPFilter.java │ │ ├── CSPReportingFilter.java │ │ ├── CacheControlFilter.java │ │ ├── HSTSFilter.java │ │ ├── XContentTypeOptionsFilter.java │ │ ├── XFrameOptionsFilter.java │ │ └── XXSSProtectionFilter.java │ │ └── servlets │ │ ├── CSPReporting.java │ │ ├── FakeServlet.java │ │ └── LoginServlet.java │ └── webapp │ ├── WEB-INF │ └── web.xml │ ├── all │ └── all.jsp │ ├── cache-control │ ├── protected.jsp │ └── unprotected.jsp │ ├── csp │ ├── protected.jsp │ ├── reporting.jsp │ └── unprotected.jsp │ ├── csp2 │ ├── protected.jsp │ ├── protectedForm.jsp │ ├── unprotected.jsp │ └── unprotectedForm.jsp │ ├── index.jsp │ ├── resources │ └── css │ │ └── styles.css │ ├── x-content-type-options │ ├── protected.txt │ └── unprotected.txt │ ├── x-frame-options │ ├── protected.jsp │ ├── protectedForm.jsp │ ├── unprotected.jsp │ └── unprotectedForm.jsp │ └── x-xss-protection │ ├── protected.jsp │ └── unprotected.jsp ├── security-logging ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ └── logging │ │ │ ├── Application.java │ │ │ └── home │ │ │ ├── HomeController.java │ │ │ └── Login.java │ └── resources │ │ ├── logback.xml │ │ └── templates │ │ ├── index.html │ │ └── login.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── logging │ └── ApplicationTest.java ├── serialize-me ├── pom.xml └── src │ └── main │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── serialize │ ├── Deserializer.java │ ├── SerializeMe.java │ └── Serializer.java ├── session-handling-spring-security ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ └── sessionhandling │ │ │ ├── Application.java │ │ │ ├── SecurityConfig.java │ │ │ └── greetings │ │ │ ├── GreetingController.java │ │ │ └── GreetingService.java │ └── resources │ │ ├── application.yml │ │ └── templates │ │ ├── admin │ │ └── admin.html │ │ ├── index.html │ │ └── user │ │ └── user.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── sessionhandling │ └── ApplicationTest.java ├── session-handling ├── pom.xml └── src │ └── main │ ├── java │ └── de │ │ └── dominikschadow │ │ └── javasecurity │ │ └── sessionhandling │ │ └── servlets │ │ └── LoginServlet.java │ └── webapp │ ├── index.jsp │ └── resources │ └── css │ └── styles.css ├── sql-injection ├── pom.xml └── src │ ├── main │ ├── java │ │ └── de │ │ │ └── dominikschadow │ │ │ └── javasecurity │ │ │ ├── Application.java │ │ │ └── customers │ │ │ ├── Customer.java │ │ │ ├── CustomerController.java │ │ │ └── CustomerService.java │ └── resources │ │ ├── ESAPI.properties │ │ ├── application.yml │ │ ├── data.sql │ │ ├── esapi-java-logging.properties │ │ ├── schema.sql │ │ └── templates │ │ ├── index.html │ │ └── result.html │ └── test │ └── java │ └── de │ └── dominikschadow │ └── javasecurity │ └── ApplicationTest.java └── xss ├── pom.xml └── src └── main ├── java └── de │ └── dominikschadow │ └── javasecurity │ └── xss │ ├── CSPServlet.java │ ├── InputValidatedServlet.java │ ├── OutputEscapedServlet.java │ └── UnprotectedServlet.java ├── resources └── context.xml └── webapp ├── WEB-INF └── web.xml ├── alert.js ├── escaped.jsp ├── index.jsp └── resources └── css └── styles.css /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | name: JavaSecurity Build 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | - name: Configure Java 20 | uses: actions/setup-java@v4 21 | with: 22 | distribution: 'temurin' 23 | java-version: '21' 24 | cache: 'maven' 25 | - name: Build with Maven 26 | run: mvn -B package --file pom.xml 27 | - name: Generate Codecov Report 28 | uses: codecov/codecov-action@v5 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.log 3 | *.lck 4 | .Idea* 5 | target** 6 | .settings* 7 | .metadata* 8 | .classpath 9 | .project 10 | /dependency-check-report.html 11 | /serialize-me.bin 12 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 24 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 25 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 26 | 27 | /** 28 | * Starter class for the Spring Boot application. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @SpringBootApplication 33 | @EnableWebSecurity 34 | @Configuration 35 | public class Application implements WebMvcConfigurer { 36 | public static void main(String[] args) { 37 | SpringApplication.run(Application.class, args); 38 | } 39 | 40 | @Override 41 | public void addViewControllers(ViewControllerRegistry registry) { 42 | registry.addViewController("/").setViewName("index"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/java/de/dominikschadow/javasecurity/contacts/Contact.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.contacts; 19 | 20 | import jakarta.persistence.*; 21 | import jakarta.validation.constraints.Size; 22 | import lombok.Getter; 23 | import lombok.Setter; 24 | 25 | @Entity 26 | @Table(name = "contacts") 27 | @Getter 28 | @Setter 29 | public class Contact { 30 | @Id 31 | @GeneratedValue(strategy = GenerationType.AUTO) 32 | private Long id; 33 | @Size(min = 5, max = 50) 34 | private String firstname; 35 | @Size(min = 5, max = 50) 36 | private String lastname; 37 | @Size(max = 100) 38 | private String comment; 39 | @Size(min = 5, max = 50) 40 | private String username; 41 | } 42 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/java/de/dominikschadow/javasecurity/contacts/ContactController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.contacts; 19 | 20 | import lombok.RequiredArgsConstructor; 21 | import lombok.extern.slf4j.Slf4j; 22 | import org.springframework.stereotype.Controller; 23 | import org.springframework.ui.Model; 24 | import org.springframework.web.bind.annotation.GetMapping; 25 | import org.springframework.web.bind.annotation.PathVariable; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * Contact controller for all contact related operations. 32 | * 33 | * @author Dominik Schadow 34 | */ 35 | @Controller 36 | @RequestMapping(value = "/contacts") 37 | @RequiredArgsConstructor 38 | @Slf4j 39 | public class ContactController { 40 | private final ContactService contactService; 41 | 42 | @GetMapping 43 | public String list(Model model) { 44 | List contacts = contactService.getContacts(); 45 | 46 | log.info("Found {} contacts for user", contacts.size()); 47 | 48 | model.addAttribute("contacts", contacts); 49 | 50 | return "contacts/list"; 51 | } 52 | 53 | @GetMapping("{contactId}") 54 | public String details(@PathVariable int contactId, Model model) { 55 | log.info("Loading contact with ID {} for user", contactId); 56 | 57 | Contact contact = contactService.getContact(contactId); 58 | 59 | model.addAttribute("contact", contact); 60 | 61 | return "contacts/details"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | main: 3 | web-application-type: servlet 4 | datasource: 5 | username: sa 6 | password: sa 7 | name: access-control 8 | h2: 9 | console: 10 | enabled: true 11 | jpa: 12 | hibernate: 13 | ddl-auto: none -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into contacts (username, firstname, lastname, comment) values ('userA', 'Zaphod', 'Beeblebrox', 'President'); 2 | insert into contacts (username, firstname, lastname, comment) values ('userA', 'Ford', 'Prefect', 'Researcher for the Hitchhiker''s Guide to the Galaxy'); 3 | 4 | insert into contacts (username, firstname, lastname, comment) values ('userB', 'Arthur', 'Dent', 'BBC Radio employee'); 5 | insert into contacts (username, firstname, lastname, comment) values ('userB', 'Tricia Marie', 'McMillan', ''); -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE contacts ( 2 | id BIGINT NOT NULL AUTO_INCREMENT, 3 | username VARCHAR(50) NOT NULL, 4 | firstname VARCHAR(50) NOT NULL, 5 | lastname VARCHAR(50) NOT NULL, 6 | comment VARCHAR(100) NOT NULL, 7 | PRIMARY KEY (id)); 8 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/templates/contacts/details.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Access Control - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Contact Details

15 |
16 |
17 | 18 |
19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
IDFirstnameLastnameComment
39 |
40 |
41 |
42 | 43 |
44 |
45 | All Contacts | Logout 46 |
47 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/templates/contacts/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Access Control - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

All Contacts 15 | 16 |

17 |
18 |
19 | 20 |
21 |
22 |
23 |
    24 |
  • 25 | 26 |
  • 27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 | Logout 35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /access-control-spring-security/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Access Control - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Access Control - Spring Security

15 |

This application shows you how Spring Security enables you to automatically filter the returned results 16 | based on the currently logged-in user.

17 |
18 |
19 | 20 |
21 |
22 |

First Task

23 |

Log in and list all contacts for the selected user. Two users are available: 24 | userA/userA and userB/userB.

25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /access-control-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /crypto-hash/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | crypto-hash 12 | jar 13 | Crypto Hash 14 | 15 | Java hashing sample project using Java capabilities to hash passwords. Each class has its own tests to 16 | demonstrate various aspects. 17 | 18 | 19 | 20 | 21 | com.google.guava 22 | guava 23 | test 24 | 25 | 26 | 27 | org.junit.jupiter 28 | junit-jupiter 29 | test 30 | 31 | 32 | -------------------------------------------------------------------------------- /crypto-hash/src/main/java/de/dominikschadow/javasecurity/hash/MD5.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import java.nio.charset.StandardCharsets; 21 | import java.security.MessageDigest; 22 | import java.security.NoSuchAlgorithmException; 23 | 24 | import static de.dominikschadow.javasecurity.hash.PasswordComparator.comparePasswords; 25 | 26 | /** 27 | * MD5 hashing sample with plain Java. No salt and no iterations are used to calculate the hash value. This sample (and 28 | * the MD5 algorithm) is totally insecure. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | public class MD5 { 33 | private static final String ALGORITHM = "MD5"; 34 | 35 | public byte[] calculateHash(String password) throws NoSuchAlgorithmException { 36 | MessageDigest md = MessageDigest.getInstance(ALGORITHM); 37 | md.reset(); 38 | md.update(password.getBytes(StandardCharsets.UTF_8)); 39 | return md.digest(); 40 | } 41 | 42 | public boolean verifyPassword(byte[] originalHash, String password) throws NoSuchAlgorithmException { 43 | byte[] comparisonHash = calculateHash(password); 44 | 45 | return comparePasswords(originalHash, comparisonHash); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /crypto-hash/src/main/java/de/dominikschadow/javasecurity/hash/PBKDF2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import javax.crypto.SecretKeyFactory; 21 | import javax.crypto.spec.PBEKeySpec; 22 | import java.security.NoSuchAlgorithmException; 23 | import java.security.SecureRandom; 24 | import java.security.spec.InvalidKeySpecException; 25 | 26 | import static de.dominikschadow.javasecurity.hash.PasswordComparator.comparePasswords; 27 | 28 | /** 29 | * PBKDF2 hashing sample with plain Java. Uses a salt, configures the number of iterations and calculates the hash 30 | * value. 31 | * 32 | * @author Dominik Schadow 33 | */ 34 | public class PBKDF2 { 35 | private static final String ALGORITHM = "PBKDF2WithHmacSHA512"; 36 | private static final int ITERATIONS = 10000; 37 | // salt size at least 32 byte 38 | private static final int SALT_SIZE = 32; 39 | private static final int HASH_SIZE = 512; 40 | 41 | public SecretKeyFactory createSecretKeyFactory() throws NoSuchAlgorithmException { 42 | return SecretKeyFactory.getInstance(ALGORITHM); 43 | } 44 | 45 | public byte[] generateSalt() { 46 | SecureRandom random = new SecureRandom(); 47 | byte[] salt = new byte[SALT_SIZE]; 48 | random.nextBytes(salt); 49 | 50 | return salt; 51 | } 52 | 53 | public byte[] calculateHash(SecretKeyFactory skf, char[] password, byte[] salt) throws InvalidKeySpecException { 54 | PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, HASH_SIZE); 55 | byte[] hash = skf.generateSecret(spec).getEncoded(); 56 | spec.clearPassword(); 57 | 58 | return hash; 59 | } 60 | 61 | public boolean verifyPassword(SecretKeyFactory skf, byte[] originalHash, char[] password, byte[] salt) throws 62 | InvalidKeySpecException { 63 | byte[] comparisonHash = calculateHash(skf, password, salt); 64 | 65 | return comparePasswords(originalHash, comparisonHash); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /crypto-hash/src/main/java/de/dominikschadow/javasecurity/hash/PasswordComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | public class PasswordComparator { 21 | /** 22 | * Compares the two byte arrays in length-constant time using XOR. 23 | * 24 | * @param originalHash The original password hash 25 | * @param comparisonHash The comparison password hash 26 | * @return True if both match, false otherwise 27 | */ 28 | public static boolean comparePasswords(byte[] originalHash, byte[] comparisonHash) { 29 | int diff = originalHash.length ^ comparisonHash.length; 30 | for (int i = 0; i < originalHash.length && i < comparisonHash.length; i++) { 31 | diff |= originalHash[i] ^ comparisonHash[i]; 32 | } 33 | 34 | return diff == 0; 35 | } 36 | } -------------------------------------------------------------------------------- /crypto-hash/src/test/java/de/dominikschadow/javasecurity/hash/MD5Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import com.google.common.hash.HashCode; 21 | import org.junit.jupiter.api.Assertions; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | class MD5Test { 27 | private final MD5 md5 = new MD5(); 28 | 29 | @Test 30 | void givenIdenticalPasswordsWhenComparingHashesReturnsTrue() throws Exception { 31 | String password = "TotallySecurePassword12345"; 32 | 33 | byte[] originalHash = md5.calculateHash(password); 34 | boolean hashMatches = md5.verifyPassword(originalHash, password); 35 | 36 | Assertions.assertAll( 37 | () -> assertEquals("6ee66e42a8e60d5fb816030b188c4c79", HashCode.fromBytes(originalHash).toString()), 38 | () -> assertTrue(hashMatches) 39 | ); 40 | } 41 | 42 | @Test 43 | void givenNotIdenticalPasswordsWhenComparingHashesReturnsFalse() throws Exception { 44 | String password = "TotallySecurePassword12345"; 45 | 46 | byte[] originalHash = md5.calculateHash(password); 47 | boolean hashMatches = md5.verifyPassword(originalHash, "fakePassword12345"); 48 | 49 | Assertions.assertAll( 50 | () -> assertEquals("6ee66e42a8e60d5fb816030b188c4c79", HashCode.fromBytes(originalHash).toString()), 51 | () -> assertFalse(hashMatches) 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /crypto-hash/src/test/java/de/dominikschadow/javasecurity/hash/PBKDF2Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import org.junit.jupiter.api.Assertions; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import javax.crypto.SecretKeyFactory; 24 | 25 | import static org.junit.jupiter.api.Assertions.*; 26 | 27 | class PBKDF2Test { 28 | private final PBKDF2 pbkdf2 = new PBKDF2(); 29 | 30 | @Test 31 | void givenIdenticalPasswordsWhenComparingHashesReturnsTrue() throws Exception { 32 | char[] password = "TotallySecurePassword12345".toCharArray(); 33 | 34 | SecretKeyFactory skf = pbkdf2.createSecretKeyFactory(); 35 | byte[] salt = pbkdf2.generateSalt(); 36 | byte[] originalHash = pbkdf2.calculateHash(skf, password, salt); 37 | boolean hashMatches = pbkdf2.verifyPassword(skf, originalHash, password, salt); 38 | 39 | Assertions.assertAll( 40 | () -> assertNotNull(skf), 41 | () -> assertNotNull(salt), 42 | () -> assertNotNull(originalHash), 43 | () -> assertTrue(hashMatches) 44 | ); 45 | } 46 | 47 | @Test 48 | void givenNotIdenticalPasswordsWhenComparingHashesReturnsFalse() throws Exception { 49 | char[] password = "TotallySecurePassword12345".toCharArray(); 50 | 51 | SecretKeyFactory skf = pbkdf2.createSecretKeyFactory(); 52 | byte[] salt = pbkdf2.generateSalt(); 53 | byte[] originalHash = pbkdf2.calculateHash(skf, password, salt); 54 | boolean hashMatches = pbkdf2.verifyPassword(skf, originalHash, "fakePassword12345".toCharArray(), salt); 55 | 56 | Assertions.assertAll( 57 | () -> assertNotNull(skf), 58 | () -> assertNotNull(salt), 59 | () -> assertNotNull(originalHash), 60 | () -> assertFalse(hashMatches) 61 | ); 62 | } 63 | } -------------------------------------------------------------------------------- /crypto-hash/src/test/java/de/dominikschadow/javasecurity/hash/SHA512Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import org.junit.jupiter.api.Assertions; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static org.junit.jupiter.api.Assertions.*; 24 | 25 | class SHA512Test { 26 | private final SHA512 sha512 = new SHA512(); 27 | 28 | @Test 29 | void givenIdenticalPasswordsWhenComparingHashesReturnsTrue() throws Exception { 30 | String password = "TotallySecurePassword12345"; 31 | 32 | byte[] salt = sha512.generateSalt(); 33 | byte[] originalHash = sha512.calculateHash(password, salt); 34 | boolean hashMatches = sha512.verifyPassword(originalHash, password, salt); 35 | 36 | Assertions.assertAll( 37 | () -> assertNotNull(salt), 38 | () -> assertNotNull(originalHash), 39 | () -> assertTrue(hashMatches) 40 | ); 41 | } 42 | 43 | @Test 44 | void givenNotIdenticalPasswordsWhenComparingHashesReturnsFalse() throws Exception { 45 | String password = "TotallySecurePassword12345"; 46 | 47 | byte[] salt = sha512.generateSalt(); 48 | byte[] originalHash = sha512.calculateHash(password, salt); 49 | boolean hashMatches = sha512.verifyPassword(originalHash, "fakePassword12345", salt); 50 | 51 | Assertions.assertAll( 52 | () -> assertNotNull(salt), 53 | () -> assertNotNull(originalHash), 54 | () -> assertFalse(hashMatches) 55 | ); 56 | } 57 | } -------------------------------------------------------------------------------- /crypto-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | crypto-java 12 | jar 13 | Crypto Java 14 | 15 | Java crypto sample project using Java capabilities to encrypt and decrypt data. Each class has its own 16 | tests to demonstrate various aspects. 17 | 18 | 19 | 20 | 21 | org.junit.jupiter 22 | junit-jupiter 23 | test 24 | 25 | 26 | -------------------------------------------------------------------------------- /crypto-java/src/main/java/de/dominikschadow/javasecurity/Keystore.java: -------------------------------------------------------------------------------- 1 | package de.dominikschadow.javasecurity; 2 | 3 | import de.dominikschadow.javasecurity.asymmetric.DSA; 4 | 5 | import javax.crypto.spec.SecretKeySpec; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.security.*; 9 | import java.security.cert.CertificateException; 10 | 11 | public class Keystore { 12 | private static final String KEYSTORE_PATH = "/samples.ks"; 13 | 14 | public static KeyStore loadKeystore(char[] keystorePassword) throws KeyStoreException, 15 | CertificateException, NoSuchAlgorithmException, IOException { 16 | try (InputStream keystoreStream = DSA.class.getResourceAsStream(KEYSTORE_PATH)) { 17 | KeyStore ks = KeyStore.getInstance("JCEKS"); 18 | ks.load(keystoreStream, keystorePassword); 19 | return ks; 20 | } 21 | } 22 | 23 | public static PrivateKey loadPrivateKey(KeyStore ks, String keyAlias, char[] keyPassword) throws KeyStoreException, 24 | UnrecoverableKeyException, NoSuchAlgorithmException { 25 | if (!ks.containsAlias(keyAlias)) { 26 | throw new UnrecoverableKeyException("Private key " + keyAlias + " not found in keystore"); 27 | } 28 | 29 | return (PrivateKey) ks.getKey(keyAlias, keyPassword); 30 | } 31 | 32 | public static PublicKey loadPublicKey(KeyStore ks, String keyAlias) throws KeyStoreException, UnrecoverableKeyException { 33 | if (!ks.containsAlias(keyAlias)) { 34 | throw new UnrecoverableKeyException("Public key " + keyAlias + " not found in keystore"); 35 | } 36 | 37 | return ks.getCertificate(keyAlias).getPublicKey(); 38 | } 39 | 40 | public static Key loadKey(KeyStore ks, String keyAlias, char[] keyPassword) throws KeyStoreException, 41 | UnrecoverableKeyException, NoSuchAlgorithmException { 42 | if (!ks.containsAlias(keyAlias)) { 43 | throw new UnrecoverableKeyException("Secret key " + keyAlias + " not found in keystore"); 44 | } 45 | 46 | return ks.getKey(keyAlias, keyPassword); 47 | } 48 | 49 | public static SecretKeySpec createSecretKeySpec(byte[] key, String algorithm) { 50 | return new SecretKeySpec(key, algorithm); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /crypto-java/src/main/java/de/dominikschadow/javasecurity/asymmetric/DSA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.asymmetric; 19 | 20 | import java.nio.charset.StandardCharsets; 21 | import java.security.*; 22 | 23 | /** 24 | * Digital signature sample with plain Java. Loads the DSA key from the sample keystore, signs and verifies sample text 25 | * with it. 26 | *

27 | * Uses Google Guava to hex the encrypted message as readable format. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | public class DSA { 32 | private static final String ALGORITHM = "SHA1withDSA"; 33 | 34 | public byte[] sign(PrivateKey privateKey, String initialText) throws NoSuchAlgorithmException, 35 | InvalidKeyException, SignatureException { 36 | Signature dsa = Signature.getInstance(ALGORITHM); 37 | dsa.initSign(privateKey); 38 | dsa.update(initialText.getBytes(StandardCharsets.UTF_8)); 39 | return dsa.sign(); 40 | } 41 | 42 | public boolean verify(PublicKey publicKey, byte[] signature, String initialText) throws 43 | NoSuchAlgorithmException, InvalidKeyException, SignatureException { 44 | Signature dsa = Signature.getInstance(ALGORITHM); 45 | dsa.initVerify(publicKey); 46 | dsa.update(initialText.getBytes(StandardCharsets.UTF_8)); 47 | return dsa.verify(signature); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /crypto-java/src/main/java/de/dominikschadow/javasecurity/asymmetric/RSA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.asymmetric; 19 | 20 | import javax.crypto.BadPaddingException; 21 | import javax.crypto.Cipher; 22 | import javax.crypto.IllegalBlockSizeException; 23 | import javax.crypto.NoSuchPaddingException; 24 | import java.nio.charset.StandardCharsets; 25 | import java.security.InvalidKeyException; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.security.PrivateKey; 28 | import java.security.PublicKey; 29 | 30 | /** 31 | * Asymmetric encryption sample with plain Java. Loads the RSA key from the sample keystore, encrypts and decrypts 32 | * sample text with it. 33 | *

34 | * Uses Google Guava to hex the encrypted message as readable format. 35 | * 36 | * @author Dominik Schadow 37 | */ 38 | public class RSA { 39 | private static final String ALGORITHM = "RSA"; 40 | 41 | public byte[] encrypt(PublicKey publicKey, String initialText) throws NoSuchPaddingException, 42 | NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { 43 | Cipher cipher = Cipher.getInstance(ALGORITHM); 44 | cipher.init(Cipher.ENCRYPT_MODE, publicKey); 45 | return cipher.doFinal(initialText.getBytes(StandardCharsets.UTF_8)); 46 | } 47 | 48 | public byte[] decrypt(PrivateKey privateKey, byte[] ciphertext) throws NoSuchPaddingException, 49 | NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { 50 | Cipher cipher = Cipher.getInstance(ALGORITHM); 51 | cipher.init(Cipher.DECRYPT_MODE, privateKey); 52 | return cipher.doFinal(ciphertext); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /crypto-java/src/main/resources/samples.ks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/crypto-java/src/main/resources/samples.ks -------------------------------------------------------------------------------- /crypto-java/src/test/java/de/dominikschadow/javasecurity/asymmetric/RSATest.java: -------------------------------------------------------------------------------- 1 | package de.dominikschadow.javasecurity.asymmetric; 2 | 3 | import de.dominikschadow.javasecurity.Keystore; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.security.KeyStore; 9 | import java.security.PrivateKey; 10 | import java.security.PublicKey; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 14 | 15 | class RSATest { 16 | private final RSA rsa = new RSA(); 17 | private PrivateKey privateKey; 18 | private PublicKey publicKey; 19 | 20 | @BeforeEach 21 | protected void setup() throws Exception { 22 | final char[] keystorePassword = "samples".toCharArray(); 23 | final String keyAlias = "asymmetric-sample-rsa"; 24 | final char[] keyPassword = "asymmetric-sample-rsa".toCharArray(); 25 | 26 | KeyStore ks = Keystore.loadKeystore(keystorePassword); 27 | privateKey = Keystore.loadPrivateKey(ks, keyAlias, keyPassword); 28 | publicKey = Keystore.loadPublicKey(ks, keyAlias); 29 | } 30 | 31 | @Test 32 | void givenCorrectCiphertextWhenDecryptingThenReturnPlaintext() throws Exception { 33 | final String initialText = "RSA encryption sample text"; 34 | 35 | byte[] ciphertext = rsa.encrypt(publicKey, initialText); 36 | byte[] plaintext = rsa.decrypt(privateKey, ciphertext); 37 | 38 | Assertions.assertAll( 39 | () -> assertNotEquals(initialText, new String(ciphertext)), 40 | () -> assertEquals(initialText, new String(plaintext)) 41 | ); 42 | } 43 | } -------------------------------------------------------------------------------- /crypto-java/src/test/java/de/dominikschadow/javasecurity/symmetric/AESTest.java: -------------------------------------------------------------------------------- 1 | package de.dominikschadow.javasecurity.symmetric; 2 | 3 | import de.dominikschadow.javasecurity.Keystore; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.Key; 10 | import java.security.KeyStore; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 14 | 15 | class AESTest { 16 | private AES aes; 17 | 18 | @BeforeEach 19 | protected void setup() throws Exception { 20 | final char[] keystorePassword = "samples".toCharArray(); 21 | final String keyAlias = "symmetric-sample"; 22 | final char[] keyPassword = "symmetric-sample".toCharArray(); 23 | 24 | KeyStore ks = Keystore.loadKeystore(keystorePassword); 25 | Key key = Keystore.loadKey(ks, keyAlias, keyPassword); 26 | SecretKeySpec secretKeySpec = Keystore.createSecretKeySpec(key.getEncoded(), "AES"); 27 | 28 | aes = new AES(secretKeySpec, "AES/CBC/PKCS5Padding"); 29 | } 30 | 31 | @Test 32 | void givenCorrectCiphertextWhenDecryptingThenReturnPlaintext() throws Exception { 33 | final String initialText = "AES encryption sample text"; 34 | 35 | byte[] ciphertext = aes.encrypt(initialText); 36 | byte[] plaintext = aes.decrypt(ciphertext); 37 | 38 | Assertions.assertAll( 39 | () -> assertNotEquals(initialText, new String(ciphertext)), 40 | () -> assertEquals(initialText, new String(plaintext)) 41 | ); 42 | } 43 | } -------------------------------------------------------------------------------- /crypto-shiro/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | crypto-shiro 12 | jar 13 | Crypto Shiro 14 | 15 | Java crypto sample project using Apache Shiro to hash and encrypt data. Each class has its own 16 | tests to demonstrate various aspects. 17 | 18 | 19 | 20 | 21 | org.apache.shiro 22 | shiro-core 23 | 24 | 25 | 26 | org.junit.jupiter 27 | junit-jupiter 28 | test 29 | 30 | 31 | -------------------------------------------------------------------------------- /crypto-shiro/src/main/java/de/dominikschadow/javasecurity/Keystore.java: -------------------------------------------------------------------------------- 1 | package de.dominikschadow.javasecurity; 2 | 3 | import de.dominikschadow.javasecurity.symmetric.AES; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.security.*; 8 | import java.security.cert.CertificateException; 9 | 10 | public class Keystore { 11 | private static final String KEYSTORE_PATH = "/samples.ks"; 12 | 13 | public static KeyStore loadKeystore(char[] keystorePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { 14 | try (InputStream keystoreStream = AES.class.getResourceAsStream(KEYSTORE_PATH)) { 15 | KeyStore ks = KeyStore.getInstance("JCEKS"); 16 | ks.load(keystoreStream, keystorePassword); 17 | 18 | return ks; 19 | } 20 | } 21 | 22 | public static Key loadKey(KeyStore ks, String keyAlias, char[] keyPassword) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { 23 | if (!ks.containsAlias(keyAlias)) { 24 | throw new UnrecoverableKeyException("Secret key " + keyAlias + " not found in keystore"); 25 | } 26 | 27 | return ks.getKey(keyAlias, keyPassword); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crypto-shiro/src/main/java/de/dominikschadow/javasecurity/hash/SHA512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import org.apache.shiro.crypto.hash.DefaultHashService; 21 | import org.apache.shiro.crypto.hash.Hash; 22 | import org.apache.shiro.crypto.hash.HashRequest; 23 | import org.apache.shiro.lang.util.ByteSource; 24 | 25 | import java.util.Arrays; 26 | 27 | /** 28 | * SHA512 hashing sample with Apache Shiro. Uses a private base salt, configures the number of iterations, automatically 29 | * generates a salt and calculates the hash value. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | public class SHA512 { 34 | /** 35 | * Nothing up my sleeve number as private salt, not good for production. 36 | */ 37 | private static final byte[] PRIVATE_SALT_BYTES = {3, 1, 4, 1, 5, 9, 2, 6, 5}; 38 | 39 | public Hash calculateHash(String password) { 40 | ByteSource privateSalt = ByteSource.Util.bytes(PRIVATE_SALT_BYTES); 41 | DefaultHashService hashService = new DefaultHashService(); 42 | 43 | HashRequest.Builder builder = new HashRequest.Builder(); 44 | builder.setSource(ByteSource.Util.bytes(password)); 45 | builder.setSalt(privateSalt); 46 | builder.setAlgorithmName("SHA-512"); 47 | 48 | return hashService.computeHash(builder.build()); 49 | } 50 | 51 | public boolean verifyPassword(byte[] originalHash, ByteSource publicSalt, String password) { 52 | DefaultHashService hashService = new DefaultHashService(); 53 | 54 | HashRequest.Builder builder = new HashRequest.Builder(); 55 | builder.setSource(ByteSource.Util.bytes(password)); 56 | builder.setSalt(publicSalt); 57 | builder.setAlgorithmName("SHA-512"); 58 | 59 | Hash comparisonHash = hashService.computeHash(builder.build()); 60 | 61 | return Arrays.equals(originalHash, comparisonHash.getBytes()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /crypto-shiro/src/main/java/de/dominikschadow/javasecurity/symmetric/AES.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.symmetric; 19 | 20 | 21 | import org.apache.shiro.crypto.cipher.AesCipherService; 22 | import org.apache.shiro.lang.util.ByteSource; 23 | 24 | import java.security.Key; 25 | 26 | /** 27 | * Symmetric encryption sample with Apache Shiro. Loads the AES key from the sample keystore, encrypts and decrypts sample text with it. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | public class AES { 32 | /** 33 | * Encrypts the given text using all Shiro defaults: 128 bit size, CBC mode, PKCS5 padding scheme. 34 | * 35 | * @param key The key to use 36 | * @param initialText The text to encrypt 37 | * @return The encrypted text 38 | */ 39 | public byte[] encrypt(Key key, byte[] initialText) { 40 | AesCipherService cipherService = new AesCipherService(); 41 | ByteSource cipherText = cipherService.encrypt(initialText, key.getEncoded()); 42 | 43 | return cipherText.getBytes(); 44 | } 45 | 46 | public byte[] decrypt(Key key, byte[] ciphertext) { 47 | AesCipherService cipherService = new AesCipherService(); 48 | return cipherService.decrypt(ciphertext, key.getEncoded()).getClonedBytes(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /crypto-shiro/src/main/resources/samples.ks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/crypto-shiro/src/main/resources/samples.ks -------------------------------------------------------------------------------- /crypto-shiro/src/test/java/de/dominikschadow/javasecurity/hash/SHA512Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.hash; 19 | 20 | import org.apache.shiro.crypto.hash.Hash; 21 | import org.junit.jupiter.api.Assertions; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | class SHA512Test { 27 | private final SHA512 sha512 = new SHA512(); 28 | 29 | @Test 30 | void givenIdenticalPasswordsWhenComparingHashesReturnsTrue() { 31 | String password = "TotallySecurePassword12345"; 32 | 33 | Hash hash = sha512.calculateHash(password); 34 | boolean hashMatches = sha512.verifyPassword(hash.getBytes(), hash.getSalt(), password); 35 | 36 | Assertions.assertAll( 37 | () -> assertNotNull(hash.getSalt()), 38 | () -> assertNotNull(hash.getBytes()), 39 | () -> assertEquals(50000, hash.getIterations()), 40 | () -> assertEquals("SHA-512", hash.getAlgorithmName()), 41 | () -> assertTrue(hashMatches) 42 | ); 43 | } 44 | 45 | @Test 46 | void givenNotIdenticalPasswordsWhenComparingHashesReturnsFalse() { 47 | String password = "TotallySecurePassword12345"; 48 | 49 | Hash hash = sha512.calculateHash(password); 50 | boolean hashMatches = sha512.verifyPassword(hash.getBytes(), hash.getSalt(), "fakePassword12345"); 51 | 52 | Assertions.assertAll( 53 | () -> assertNotNull(hash.getSalt()), 54 | () -> assertNotNull(hash.getBytes()), 55 | () -> assertEquals(50000, hash.getIterations()), 56 | () -> assertEquals("SHA-512", hash.getAlgorithmName()), 57 | () -> assertFalse(hashMatches) 58 | ); 59 | } 60 | } -------------------------------------------------------------------------------- /crypto-shiro/src/test/java/de/dominikschadow/javasecurity/symmetric/AESTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.symmetric; 19 | 20 | import de.dominikschadow.javasecurity.Keystore; 21 | import org.apache.shiro.lang.codec.CodecSupport; 22 | import org.junit.jupiter.api.Assertions; 23 | import org.junit.jupiter.api.BeforeEach; 24 | import org.junit.jupiter.api.Test; 25 | 26 | import java.security.Key; 27 | import java.security.KeyStore; 28 | 29 | import static org.junit.jupiter.api.Assertions.assertEquals; 30 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 31 | 32 | class AESTest { 33 | private final AES aes = new AES(); 34 | private Key key; 35 | 36 | @BeforeEach 37 | protected void setup() throws Exception { 38 | final char[] keystorePassword = "samples".toCharArray(); 39 | final String keyAlias = "symmetric-sample"; 40 | final char[] keyPassword = "symmetric-sample".toCharArray(); 41 | 42 | KeyStore ks = Keystore.loadKeystore(keystorePassword); 43 | key = Keystore.loadKey(ks, keyAlias, keyPassword); 44 | } 45 | 46 | @Test 47 | void givenCorrectCiphertextWhenDecryptingThenReturnPlaintext() { 48 | final String initialText = "AES encryption sample text"; 49 | 50 | byte[] ciphertext = aes.encrypt(key, CodecSupport.toBytes(initialText)); 51 | byte[] plaintext = aes.decrypt(key, ciphertext); 52 | 53 | Assertions.assertAll( 54 | () -> assertNotEquals(initialText, new String(ciphertext)), 55 | () -> assertEquals(initialText, new String(plaintext)) 56 | ); 57 | } 58 | } -------------------------------------------------------------------------------- /crypto-tink/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | javasecurity 7 | de.dominikschadow.javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | crypto-tink 12 | jar 13 | Crypto Tink 14 | 15 | Java crypto sample project using Google Tink to encrypt/ decrypt and sign/ verify data. Each class has 16 | its own tests to demonstrate various aspects. 17 | 18 | 19 | 20 | 21 | com.google.crypto.tink 22 | tink 23 | 24 | 25 | com.google.crypto.tink 26 | tink-awskms 27 | 28 | 29 | org.apache.httpcomponents 30 | httpclient 31 | 32 | 33 | javax.xml.bind 34 | jaxb-api 35 | 36 | 37 | 38 | org.junit.jupiter 39 | junit-jupiter 40 | test 41 | 42 | 43 | -------------------------------------------------------------------------------- /crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/aead/AesEaxWithGeneratedKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.aead; 19 | 20 | import com.google.crypto.tink.Aead; 21 | import com.google.crypto.tink.KeyTemplates; 22 | import com.google.crypto.tink.KeysetHandle; 23 | import com.google.crypto.tink.aead.AeadConfig; 24 | 25 | import java.security.GeneralSecurityException; 26 | 27 | /** 28 | * Shows crypto usage with Google Tink for the Authenticated Encryption with Associated Data (AEAD) primitive. The used 29 | * key is generated during runtime and not saved. Selected algorithm is AES-EAX with 256 bit. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | public class AesEaxWithGeneratedKey { 34 | /** 35 | * Init AeadConfig in the Tink library. 36 | */ 37 | public AesEaxWithGeneratedKey() throws GeneralSecurityException { 38 | AeadConfig.register(); 39 | } 40 | 41 | public KeysetHandle generateKey() throws GeneralSecurityException { 42 | return KeysetHandle.generateNew(KeyTemplates.get("AES256_EAX")); 43 | } 44 | 45 | public byte[] encrypt(KeysetHandle keysetHandle, byte[] initialText, byte[] associatedData) throws GeneralSecurityException { 46 | Aead aead = keysetHandle.getPrimitive(Aead.class); 47 | 48 | return aead.encrypt(initialText, associatedData); 49 | } 50 | 51 | public byte[] decrypt(KeysetHandle keysetHandle, byte[] cipherText, byte[] associatedData) throws GeneralSecurityException { 52 | Aead aead = keysetHandle.getPrimitive(Aead.class); 53 | 54 | return aead.decrypt(cipherText, associatedData); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.hybrid; 19 | 20 | import com.google.crypto.tink.HybridDecrypt; 21 | import com.google.crypto.tink.HybridEncrypt; 22 | import com.google.crypto.tink.KeyTemplates; 23 | import com.google.crypto.tink.KeysetHandle; 24 | import com.google.crypto.tink.hybrid.HybridConfig; 25 | 26 | import java.security.GeneralSecurityException; 27 | 28 | /** 29 | * Shows crypto usage with Google Tink for the HybridEncrypt primitive. The used key is generated during runtime and not 30 | * saved. Selected algorithm is ECIES with AEAD and HKDF. 31 | * 32 | * @author Dominik Schadow 33 | */ 34 | public class EciesWithGeneratedKey { 35 | /** 36 | * Init HybridConfig in the Tink library. 37 | */ 38 | public EciesWithGeneratedKey() throws GeneralSecurityException { 39 | HybridConfig.register(); 40 | } 41 | 42 | public KeysetHandle generatePrivateKey() throws GeneralSecurityException { 43 | return KeysetHandle.generateNew(KeyTemplates.get("ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256")); 44 | } 45 | 46 | public KeysetHandle generatePublicKey(KeysetHandle privateKeysetHandle) throws GeneralSecurityException { 47 | return privateKeysetHandle.getPublicKeysetHandle(); 48 | } 49 | 50 | public byte[] encrypt(KeysetHandle publicKeysetHandle, byte[] initialText, byte[] contextInfo) throws GeneralSecurityException { 51 | HybridEncrypt hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt.class); 52 | 53 | return hybridEncrypt.encrypt(initialText, contextInfo); 54 | } 55 | 56 | public byte[] decrypt(KeysetHandle privateKeysetHandle, byte[] cipherText, byte[] contextInfo) throws GeneralSecurityException { 57 | HybridDecrypt hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt.class); 58 | 59 | return hybridDecrypt.decrypt(cipherText, contextInfo); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crypto-tink/src/main/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.mac; 19 | 20 | import com.google.crypto.tink.KeyTemplates; 21 | import com.google.crypto.tink.KeysetHandle; 22 | import com.google.crypto.tink.Mac; 23 | import com.google.crypto.tink.mac.MacConfig; 24 | 25 | import java.security.GeneralSecurityException; 26 | 27 | /** 28 | * Shows crypto usage with Google Tink for the Hash-based Message Authentication Code (HMAC) primitive. The used key is 29 | * generated during runtime and not saved. Selected algorithm is SHA 256 with 128 bit. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | public class HmacShaWithGeneratedKey { 34 | /** 35 | * Init MacConfig in the Tink library. 36 | */ 37 | public HmacShaWithGeneratedKey() throws GeneralSecurityException { 38 | MacConfig.register(); 39 | } 40 | 41 | public byte[] computeMac(KeysetHandle keysetHandle, byte[] initialText) throws GeneralSecurityException { 42 | Mac mac = keysetHandle.getPrimitive(Mac.class); 43 | 44 | return mac.computeMac(initialText); 45 | } 46 | 47 | public boolean verifyMac(KeysetHandle keysetHandle, byte[] initialMac, byte[] initialText) { 48 | try { 49 | Mac mac = keysetHandle.getPrimitive(Mac.class); 50 | mac.verifyMac(initialMac, initialText); 51 | 52 | return true; 53 | } catch (GeneralSecurityException ex) { 54 | // MAC is invalid 55 | return false; 56 | } 57 | } 58 | 59 | public KeysetHandle generateKey() throws GeneralSecurityException { 60 | return KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG")); 61 | } 62 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/aead/AesGcmWithSavedKeyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.aead; 19 | 20 | import com.google.crypto.tink.KeysetHandle; 21 | import org.junit.jupiter.api.Assertions; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | 25 | import java.io.File; 26 | import java.nio.charset.StandardCharsets; 27 | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; 29 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 30 | 31 | class AesGcmWithSavedKeyTest { 32 | private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8); 33 | private static final byte[] ASSOCIATED_DATA = "Some additional data".getBytes(StandardCharsets.UTF_8); 34 | private static final String KEYSET_FILENAME = "src/test/resources/keysets/aead-aes-gcm.json"; 35 | private final File keysetFile = new File(KEYSET_FILENAME); 36 | private KeysetHandle secretKey; 37 | 38 | private AesGcmWithSavedKey aes; 39 | 40 | @BeforeEach 41 | protected void setup() throws Exception { 42 | aes = new AesGcmWithSavedKey(); 43 | 44 | aes.generateAndStoreKey(keysetFile); 45 | secretKey = aes.loadKey(keysetFile); 46 | } 47 | 48 | @Test 49 | void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception { 50 | byte[] cipherText = aes.encrypt(secretKey, INITIAL_TEXT, ASSOCIATED_DATA); 51 | byte[] plainText = aes.decrypt(secretKey, cipherText, ASSOCIATED_DATA); 52 | 53 | Assertions.assertAll( 54 | () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)), 55 | () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8)) 56 | ); 57 | } 58 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/hybrid/EciesWithGeneratedKeyAndKeyRotationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.hybrid; 19 | 20 | import com.google.crypto.tink.KeysetHandle; 21 | import org.junit.jupiter.api.Assertions; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | 25 | import java.nio.charset.StandardCharsets; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 29 | 30 | class EciesWithGeneratedKeyAndKeyRotationTest { 31 | private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8); 32 | private static final byte[] CONTEXT_INFO = "Some additional data".getBytes(StandardCharsets.UTF_8); 33 | 34 | private EciesWithGeneratedKeyAndKeyRotation ecies; 35 | 36 | @BeforeEach 37 | protected void setup() throws Exception { 38 | ecies = new EciesWithGeneratedKeyAndKeyRotation(); 39 | } 40 | 41 | @Test 42 | void encryptionAndDecryptionWithValidInputsIsSuccessful() throws Exception { 43 | KeysetHandle originalKey = ecies.generatePrivateKey(); 44 | KeysetHandle rotatedKey = ecies.rotateKey(originalKey); 45 | KeysetHandle publicKey = ecies.generatePublicKey(rotatedKey); 46 | 47 | byte[] cipherText = ecies.encrypt(publicKey, INITIAL_TEXT, CONTEXT_INFO); 48 | byte[] plainText = ecies.decrypt(rotatedKey, cipherText, CONTEXT_INFO); 49 | 50 | Assertions.assertAll( 51 | () -> assertNotEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(cipherText, StandardCharsets.UTF_8)), 52 | () -> assertNotEquals(originalKey.getKeysetInfo().getPrimaryKeyId(), rotatedKey.getKeysetInfo().getPrimaryKeyId()), 53 | () -> assertEquals(new String(INITIAL_TEXT, StandardCharsets.UTF_8), new String(plainText, StandardCharsets.UTF_8)) 54 | ); 55 | } 56 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/java/de/dominikschadow/javasecurity/tink/mac/HmacShaWithGeneratedKeyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tink.mac; 19 | 20 | import com.google.crypto.tink.KeysetHandle; 21 | import org.junit.jupiter.api.Assertions; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | 25 | import java.nio.charset.StandardCharsets; 26 | 27 | import static org.junit.jupiter.api.Assertions.*; 28 | 29 | class HmacShaWithGeneratedKeyTest { 30 | private static final byte[] INITIAL_TEXT = "Some dummy text to work with".getBytes(StandardCharsets.UTF_8); 31 | 32 | private HmacShaWithGeneratedKey hmac; 33 | 34 | @BeforeEach 35 | protected void setup() throws Exception { 36 | hmac = new HmacShaWithGeneratedKey(); 37 | } 38 | 39 | @Test 40 | void unchangedInputValidatesSuccessful() throws Exception { 41 | KeysetHandle keysetHandle = hmac.generateKey(); 42 | 43 | byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT); 44 | boolean validation = hmac.verifyMac(keysetHandle, initialMac, INITIAL_TEXT); 45 | 46 | Assertions.assertAll( 47 | () -> assertNotNull(initialMac), 48 | () -> assertTrue(validation) 49 | ); 50 | } 51 | 52 | @Test 53 | void changedInputValidationFails() throws Exception { 54 | KeysetHandle keysetHandle = hmac.generateKey(); 55 | 56 | byte[] initialMac = hmac.computeMac(keysetHandle, INITIAL_TEXT); 57 | boolean validation = hmac.verifyMac(keysetHandle, initialMac, "manipulation".getBytes(StandardCharsets.UTF_8)); 58 | 59 | Assertions.assertAll( 60 | () -> assertNotNull(initialMac), 61 | () -> assertFalse(validation) 62 | ); 63 | } 64 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/aead-aes-gcm-kms.json: -------------------------------------------------------------------------------- 1 | {"encryptedKeyset":"AQICAHjXd7WP9NB78zMSpXCiIaQEPB/K2Ud3VinJdPgxys8yuQHWCk8U1SMe+Z/R8hW6opG3AAAAvjCBuwYJKoZIhvcNAQcGoIGtMIGqAgEAMIGkBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDOLJ88WqVDo7mor5QwIBEIB3IusYc6T8mAhMFyeBN3xtOqJM1oShYrrQ6GON23dorIvFcK9uzFwk5vd5oh0Db6Zb02+f5ORGSu7McLNZvNh4NjPUz9u9E3/Vi0NLXaIMvHvXRuFVPIWWQ+dP2BN7FtRYQHQvspBOuKc4y3JM9GZFtMF6O/6XKpE=","keysetInfo":{"primaryKeyId":1300661024,"keyInfo":[{"typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey","status":"ENABLED","keyId":1300661024,"outputPrefixType":"TINK"}]}} 2 | -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/aead-aes-gcm.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 82246046, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey", 6 | "keyMaterialType": "SYMMETRIC", 7 | "value": "GhDjKEsbViapDSSELJV2+g5L" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 82246046, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/hmac-sha.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 465633422, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", 6 | "keyMaterialType": "SYMMETRIC", 7 | "value": "EgQIAxAQGiBqV52a9z22vyYxj8w4emtxDHNGUDYke04Kq2pDsK2x4Q==" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 465633422, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-private.json: -------------------------------------------------------------------------------- 1 | {"encryptedKeyset":"AQICAHjXd7WP9NB78zMSpXCiIaQEPB/K2Ud3VinJdPgxys8yuQEsHuHirJFAlSA97EngGNevAAABczCCAW8GCSqGSIb3DQEHBqCCAWAwggFcAgEAMIIBVQYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAzHlEQEosgJyOUa7fwCARCAggEm2YA+KQgvMvKDPaXW/0wBdujU/kR6O7G0EO079rL55qqTVmeRnMZN4vInQYtDVPdX9wXpASTnmDR5YBK5KAC6rOhWHBqmnbNxYr+HIuQfwNmuwcBMDHh9OEXQCxrufOrEXj/MkB9NeTlWNqmIIZmDcRsx4ry7CH4jXciUhkSl4S7oFNT1BrFo9/rKSYxUeGlnKJ5WmRiTwS+BOBZyHJpQ2rVMCbwdO+8DGU69wOInO2a6q2xG+m+5nbujNKreZTi4ovxqN0FghOvxXshY8CgmUJ6cSwupn8LFVsKIu3tEEjyqfSedd7by6DqALexPQp4dHBgIt374FjIKla1Lps9q6BfzCWaQ3TCdjUtv3K09Wz+Y2JwpsO44nLfd9mN+zHMRAdWAXjx8","keysetInfo":{"primaryKeyId":1816387889,"keyInfo":[{"typeUrl":"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey","status":"ENABLED","keyId":1816387889,"outputPrefixType":"TINK"}]}} 2 | -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/hybrid-ecies-kms-public.json: -------------------------------------------------------------------------------- 1 | {"primaryKeyId":1816387889,"key":[{"keyData":{"typeUrl":"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey","value":"EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogHp9oy6ikN+tZ7XEvCgXYHzfM5r5Lre+o8RrRYHocYy4iIQC9JUU69dvUdZAXR2ycmF2lE/E0Mkwq39vACd22tqwGiA==","keyMaterialType":"ASYMMETRIC_PUBLIC"},"status":"ENABLED","keyId":1816387889,"outputPrefixType":"TINK"}]} 2 | -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/hybrid-ecies-private.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 1484316268, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 6 | "keyMaterialType": "ASYMMETRIC_PRIVATE", 7 | "value": "EooBEkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogf6TzB94D7gKGLYQPWQKMmg59GPCvOD8Y9BovsPcjSGoiIDcXU5AoFVfzHyRwRfXWrnda7mnEDTQjXh7WC0gmF1B1GiEArZz1ig5K8JPpBN4RCEOzhppzDPBRknhWooU3dNViyoY=" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 1484316268, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/hybrid-ecies-public.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 1484316268, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", 6 | "keyMaterialType": "ASYMMETRIC_PUBLIC", 7 | "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogf6TzB94D7gKGLYQPWQKMmg59GPCvOD8Y9BovsPcjSGoiIDcXU5AoFVfzHyRwRfXWrnda7mnEDTQjXh7WC0gmF1B1" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 1484316268, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/signature-ecdsa-private.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 1264091576, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey", 6 | "keyMaterialType": "ASYMMETRIC_PRIVATE", 7 | "value": "Ek4SBggDEAIYAhohAPBvBolyjqJ1xRuheQFTJOpH5K9K+vxs0IGAOc9eX/v8IiEAuaGgQYf7Mn3NiZv7alZtQkV0zXgqKZcuZxnCNxKgaSEaIQDbsps2cueCgCBGip0WDfaY0q2HDzj0XmhRxcyx4tNbfg==" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 1264091576, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /crypto-tink/src/test/resources/keysets/signature-ecdsa-public.json: -------------------------------------------------------------------------------- 1 | { 2 | "primaryKeyId": 1264091576, 3 | "key": [{ 4 | "keyData": { 5 | "typeUrl": "type.googleapis.com/google.crypto.tink.EcdsaPublicKey", 6 | "keyMaterialType": "ASYMMETRIC_PUBLIC", 7 | "value": "EgYIAxACGAIaIQDwbwaJco6idcUboXkBUyTqR+SvSvr8bNCBgDnPXl/7/CIhALmhoEGH+zJ9zYmb+2pWbUJFdM14KimXLmcZwjcSoGkh" 8 | }, 9 | "outputPrefixType": "TINK", 10 | "keyId": 1264091576, 11 | "status": "ENABLED" 12 | }] 13 | } -------------------------------------------------------------------------------- /csp-spring-security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | csp-spring-security 12 | jar 13 | Content Security Policy - Spring Security 14 | 15 | Content Security Policy (CSP) with Spring Security sample project. Start via the main method in the 16 | Application class. After launching, open the web application in your browser at http://localhost:8080. 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-thymeleaf 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-security 31 | 32 | 33 | org.webjars 34 | bootstrap 35 | 36 | 37 | org.webjars 38 | webjars-locator-core 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | 47 | 48 | spring-boot:run 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 23 | 24 | /** 25 | * Starter class for the Spring Boot application. 26 | * 27 | * @author Dominik Schadow 28 | */ 29 | @SpringBootApplication 30 | @EnableWebSecurity 31 | public class Application { 32 | public static void main(String[] args) { 33 | SpringApplication.run(Application.class, args); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 23 | import org.springframework.security.web.SecurityFilterChain; 24 | 25 | /** 26 | * Spring Security configuration. 27 | * 28 | * @author Dominik Schadow 29 | */ 30 | @Configuration 31 | public class SecurityConfig { 32 | @Bean 33 | public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 34 | // @formatter:off 35 | http 36 | .headers() 37 | .contentSecurityPolicy("default-src 'self'"); 38 | // @formatter:on 39 | 40 | return http.build(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/Greeting.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.greetings; 19 | 20 | public record Greeting(String name) { 21 | } 22 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/java/de/dominikschadow/javasecurity/greetings/GreetingController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.greetings; 19 | 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.ui.Model; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.ModelAttribute; 24 | import org.springframework.web.bind.annotation.PostMapping; 25 | 26 | /** 27 | * Controller processing the main page and its form. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | @Controller 32 | public class GreetingController { 33 | @GetMapping("/") 34 | public String home(Model model) { 35 | model.addAttribute("greeting", new Greeting("")); 36 | 37 | return "index"; 38 | } 39 | 40 | @PostMapping("/greeting") 41 | public String greeting(Model model, @ModelAttribute Greeting greeting) { 42 | model.addAttribute("result", greeting); 43 | 44 | return "result"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Content Security Policy - Spring Security 9 | 10 | 11 |

12 |
13 |
14 |

Content Security Policy - Spring Security

15 |

This application shows you how to integrate the Content Security Policy (CSP) in a Spring Boot 16 | based web application. Since Thymeleaf automatically protects from Cross-Site Scripting this 17 | functionality is turned off explicitly. 18 |

19 |
20 |
21 | 22 |
23 |
24 |

First Task

25 |

You can see the CSP in action by trying to inject JavaScript code into the text field below. Open a 26 | browser console to see the error message for blocked content.

27 | 28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 |
38 | 39 | -------------------------------------------------------------------------------- /csp-spring-security/src/main/resources/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Content Security Policy - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Hello

15 |
16 |
17 | 18 | 19 |
20 |
21 | Try again 22 |
23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /csp-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /csrf-spring-security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | csrf-spring-security 12 | jar 13 | Cross-Site Request Forgery - Spring Security 14 | 15 | Cross-Site Request Forgery (CSRF) with Spring Security sample project. Start via the main method in the 16 | Application class. After launching, open the web application in your browser at http://localhost:8080. 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-thymeleaf 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-security 31 | 32 | 33 | org.webjars 34 | bootstrap 35 | 36 | 37 | org.webjars 38 | webjars-locator-core 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | org.springframework.security 48 | spring-security-test 49 | test 50 | 51 | 52 | 53 | 54 | spring-boot:run 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 23 | 24 | /** 25 | * Starter class for the Spring Boot application. 26 | * 27 | * @author Dominik Schadow 28 | */ 29 | @SpringBootApplication 30 | @EnableWebSecurity 31 | public class Application { 32 | public static void main(String[] args) { 33 | SpringApplication.run(Application.class, args); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 23 | import org.springframework.security.web.SecurityFilterChain; 24 | 25 | /** 26 | * Simple Spring Security configuration. Deactivates authentication and automatically protects from CSRF attacks with an 27 | * anti CSRF token. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | @Configuration 32 | public class SecurityConfig { 33 | @Bean 34 | public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 35 | // @formatter:off 36 | http 37 | .httpBasic() 38 | .disable(); 39 | // @formatter:on 40 | 41 | return http.build(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/home/IndexController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.home; 19 | 20 | import de.dominikschadow.javasecurity.orders.Order; 21 | import org.springframework.stereotype.Controller; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.ModelAttribute; 24 | import org.springframework.web.bind.annotation.RequestMapping; 25 | import org.springframework.web.bind.annotation.SessionAttributes; 26 | 27 | /** 28 | * Index controller for all home page related operations. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @Controller 33 | @RequestMapping(value = "/") 34 | @SessionAttributes("order") 35 | public class IndexController { 36 | @ModelAttribute("order") 37 | public Order order() { 38 | return new Order(""); 39 | } 40 | 41 | @GetMapping 42 | public String index(@ModelAttribute("order") Order order) { 43 | return "index"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/Order.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.orders; 19 | 20 | /** 21 | * Order entity. 22 | * 23 | * @author Dominik Schadow 24 | */ 25 | public record Order (String item) { 26 | } 27 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/java/de/dominikschadow/javasecurity/orders/OrderController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.orders; 19 | 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.web.bind.annotation.ModelAttribute; 22 | import org.springframework.web.bind.annotation.PostMapping; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | 25 | /** 26 | * Order controller for all order related operations. 27 | * 28 | * @author Dominik Schadow 29 | */ 30 | @Controller 31 | @RequestMapping(value = "/order") 32 | public class OrderController { 33 | @PostMapping() 34 | public String order(@ModelAttribute("order") Order order) { 35 | return "result"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cross-Site Request Forgery (CSRF) - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Cross-Site Request Forgery (CSRF) - Spring Security

15 |

This simple web application shows how Spring Security automatically adds an anti CSRF token to each form. 16 | You can change the token value and see how Spring rejects the request without any code required.

17 |
18 |
19 | 20 |
21 |
22 |

Automatic Anti-CSRF Token

23 |

This form contains an automatically added anti CSRF token.

24 | 25 |
26 |
27 | 28 | 29 | 30 |
31 |
32 |
33 |
34 |
35 | 36 | -------------------------------------------------------------------------------- /csrf-spring-security/src/main/resources/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cross-Site Request Forgery (CSRF) - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Cross-Site Request Forgery (CSRF) - Spring Security

15 |
16 |
17 | 18 |
19 |
20 |

You have ordered the following item:

21 |
22 |
23 | 24 |
25 |
26 | Try again 27 |
28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/home/IndexControllerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.home; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 23 | import org.springframework.security.test.context.support.WithMockUser; 24 | import org.springframework.test.web.servlet.MockMvc; 25 | 26 | import static org.hamcrest.Matchers.containsString; 27 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 28 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 29 | 30 | @WebMvcTest(IndexController.class) 31 | public class IndexControllerTest { 32 | @Autowired 33 | private MockMvc mockMvc; 34 | 35 | @Test 36 | @WithMockUser 37 | public void testHomePage() throws Exception { 38 | mockMvc.perform(get("/")) 39 | .andExpect(status().isOk()) 40 | .andExpect(view().name("index")) 41 | .andExpect(content().string(containsString("This simple web application shows"))); 42 | } 43 | } -------------------------------------------------------------------------------- /csrf-spring-security/src/test/java/de/dominikschadow/javasecurity/orders/OrderControllerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.orders; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 23 | import org.springframework.http.MediaType; 24 | import org.springframework.security.test.context.support.WithMockUser; 25 | import org.springframework.test.web.servlet.MockMvc; 26 | 27 | import static org.hamcrest.Matchers.containsString; 28 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; 29 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 30 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 31 | 32 | @WebMvcTest(OrderController.class) 33 | public class OrderControllerTest { 34 | @Autowired 35 | private MockMvc mockMvc; 36 | 37 | @Test 38 | @WithMockUser 39 | public void testWithCsrfToken() throws Exception { 40 | mockMvc.perform(post("/order").with(csrf()) 41 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 42 | .param("name", "My Item")) 43 | .andExpect(status().isOk()) 44 | .andExpect(view().name("result")) 45 | .andExpect(content().string(containsString("You have ordered the following item:"))); 46 | } 47 | 48 | @Test 49 | @WithMockUser 50 | public void testWithoutCsrfToken() throws Exception { 51 | mockMvc.perform(post("/order") 52 | .contentType(MediaType.APPLICATION_FORM_URLENCODED) 53 | .param("name", "My Item")) 54 | .andExpect(status().isForbidden()); 55 | } 56 | } -------------------------------------------------------------------------------- /csrf/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | csrf 12 | war 13 | Cross-Site Request Forgery 14 | 15 | Cross-Site Request Forgery (CSRF) sample project. Requires a server like Apache Tomcat or the Maven 16 | Tomcat7 plugin. After launching, open the web application in your browser at http://localhost:8080/csrf 17 | 18 | 19 | 20 | 21 | javax.servlet 22 | javax.servlet-api 23 | 24 | 25 | com.google.guava 26 | guava 27 | 28 | 29 | 30 | 31 | tomcat7:run-war 32 | 33 | 34 | org.apache.tomcat.maven 35 | tomcat7-maven-plugin 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /csrf/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | CSRF 7 | 8 | 9 | index.jsp 10 | 11 | 12 | 13 | 30 14 | 15 | true 16 | 17 | COOKIE 18 | 19 | -------------------------------------------------------------------------------- /csrf/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="de.dominikschadow.javasecurity.csrf.CSRFTokenHandler" %> 2 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | 8 | Cross-Site Request Forgery (CSRF) 9 | 10 | 11 |

Cross-Site Request Forgery (CSRF)

12 | 13 |
14 |
15 | Without Anti-CSRF-Token 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | With Anti-CSRF-Token 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /csrf/src/main/webapp/resources/css/styles.css: -------------------------------------------------------------------------------- 1 | .text-input { 2 | width: 250px; 3 | } 4 | 5 | h1 { 6 | font-size: 150%; 7 | } 8 | 9 | h2 { 10 | font-size: 125%; 11 | } 12 | 13 | fieldset { 14 | width: 800px; 15 | font-size: 1.2em; 16 | margin-top: 20px; 17 | } 18 | -------------------------------------------------------------------------------- /direct-object-references/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | /** 24 | * Starter class for the Spring Boot application. 25 | * 26 | * @author Dominik Schadow 27 | */ 28 | @SpringBootApplication 29 | public class Application { 30 | public static void main(String[] args) { 31 | SpringApplication.run(Application.class, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /direct-object-references/src/main/resources/ESAPI.properties: -------------------------------------------------------------------------------- 1 | # Logging 2 | Logger.ApplicationName=Direct-Object-References 3 | Logger.LogEncodingRequired=false 4 | Logger.UserInfo=false 5 | Logger.ClientInfo=false 6 | Logger.LogApplicationName=true 7 | Logger.LogServerIP=false -------------------------------------------------------------------------------- /direct-object-references/src/main/resources/static/files/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/direct-object-references/src/main/resources/static/files/cover.jpg -------------------------------------------------------------------------------- /direct-object-references/src/main/resources/static/files/cover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/direct-object-references/src/main/resources/static/files/cover.pdf -------------------------------------------------------------------------------- /direct-object-references/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Direct Object References 9 | 10 | 11 |
12 |
13 |
14 |

Direct Object References

15 |

This simple web application shows how the OWASP Enterprise Security API can mask direct references and 16 | hide them behind unpredictable indirect references.

17 |
18 |
19 | 20 |
21 |
22 |

Random Access Reference Map

23 |

The following file references are created randomly but still enable you to download the file.

24 | 25 |
    26 |
  • 27 | 28 |
  • 29 |
30 |
31 |
32 | 33 |
34 |
35 |

Direct Download

36 |

The following file references are direct references using the file name and will not work since this is 37 | not a valid entry in the reference map.

38 | 39 | 42 |
43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /direct-object-references/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /intercept-me/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | intercept-me 12 | jar 13 | Intercept Me 14 | 15 | Intercept Me sample project. Start via the main method in the Application class. After launching, open 16 | the web application in your browser at http://localhost:8080. 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-thymeleaf 27 | 28 | 29 | org.webjars 30 | bootstrap 31 | 32 | 33 | org.webjars 34 | webjars-locator-core 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-devtools 39 | runtime 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | 49 | spring-boot:run 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /intercept-me/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | /** 24 | * Starter class for the Spring Boot application. 25 | * 26 | * @author Dominik Schadow 27 | */ 28 | @SpringBootApplication 29 | public class Application { 30 | public static void main(String[] args) { 31 | SpringApplication.run(Application.class, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /intercept-me/src/main/java/de/dominikschadow/javasecurity/tasks/FirstTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tasks; 19 | 20 | /** 21 | * Domain object for the first task. 22 | * 23 | * @author Dominik Schadow 24 | */ 25 | public record FirstTask (String name) {} 26 | -------------------------------------------------------------------------------- /intercept-me/src/main/java/de/dominikschadow/javasecurity/tasks/InterceptMeController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.tasks; 19 | 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.ui.Model; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.PostMapping; 24 | import org.thymeleaf.util.StringUtils; 25 | 26 | /** 27 | * Controller processing the main page and all forms. Returns SUCCESS or FAILURE depending on the given 28 | * input. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @Controller 33 | public class InterceptMeController { 34 | @GetMapping("/") 35 | public String home(Model model) { 36 | model.addAttribute("firstTask", new FirstTask("")); 37 | 38 | return "index"; 39 | } 40 | 41 | @PostMapping("first") 42 | public String firstTask(FirstTask firstTask, Model model) { 43 | String result = "FAILURE"; 44 | 45 | if (StringUtils.equals(firstTask.name(), "inject")) { 46 | result = "SUCCESS"; 47 | } 48 | 49 | model.addAttribute("result", result); 50 | 51 | return "result"; 52 | } 53 | 54 | @PostMapping("second") 55 | public String secondTask(Model model) { 56 | model.addAttribute("result", "FAILURE"); 57 | 58 | return "result"; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /intercept-me/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Intercept Me 9 | 10 | 11 |
12 |
13 |
14 |

Intercept Me

15 |

This exercise consists of the two tasks described below. You will need OWASP ZAP or another intercepting 16 | proxy to complete them. Remember to configure OWASP ZAP and your browser first before starting the 17 | exercise.

18 |
19 |
20 | 21 |
22 |
23 |

First Task

24 |

Your first task is to use the following form to send inject (completely in lowercase) 25 | as value of the Text field so that the backend returns SUCCESS 26 | (completely in uppercase) on the resulting page. 27 |

28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |

Second Task

42 |

Your second task is to use the following form so that the backend returns SUCCESS 43 | (completely in uppercase). As you can see, this form does not contain any input field, so you have to 44 | figure out another way.

45 | 46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /intercept-me/src/main/resources/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Intercept Me 9 | 10 | 11 |
12 |
13 |
14 |

15 | Try again 16 |
17 |
18 |
19 | 20 | -------------------------------------------------------------------------------- /intercept-me/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /security-header/certificates/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/security-header/certificates/keystore.jks -------------------------------------------------------------------------------- /security-header/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | security-header 12 | war 13 | Security Header 14 | 15 | Security Response Header sample project. Sets different security related response headers via filter 16 | classes to each response. After launching, open the web application in your browser at 17 | http://localhost:8080/security-header or https://localhost:8443/security-header 18 | 19 | 20 | 21 | 22 | javax.servlet 23 | javax.servlet-api 24 | 25 | 26 | com.google.code.gson 27 | gson 28 | 29 | 30 | 31 | 32 | tomcat7:run-war 33 | 34 | 35 | org.apache.tomcat.maven 36 | tomcat7-maven-plugin 37 | 38 | 8443 39 | ${basedir}/certificates/keystore.jks 40 | secureheaders 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/CSP2Filter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code csp2/protected.jsp} page by adding the {@code Content-Security-Policy} Level 27 | * 2 header to the response. The {@code urlPatterns} should be far more wildcard in a real web application than in this 28 | * demo project. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @WebFilter(filterName = "CSP2Filter", urlPatterns = {"/csp2/protectedForm.jsp", "/all/all.jsp"}) 33 | public class CSP2Filter implements Filter { 34 | @Override 35 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 36 | FilterChain filterChain) throws IOException, ServletException { 37 | HttpServletResponse response = (HttpServletResponse) servletResponse; 38 | response.setHeader("Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'; reflected-xss block"); 39 | 40 | filterChain.doFilter(servletRequest, response); 41 | } 42 | 43 | @Override 44 | public void init(FilterConfig filterConfig) { 45 | } 46 | 47 | @Override 48 | public void destroy() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/CSPFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code csp/protected.jsp} page by adding the {@code Content-Security-Policy} header 27 | * to the response. The {@code urlPatterns} should be far more wildcard in a real web application than in this demo 28 | * project. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @WebFilter(filterName = "CSPFilter", urlPatterns = {"/csp/protected.jsp"}) 33 | public class CSPFilter implements Filter { 34 | @Override 35 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 36 | FilterChain filterChain) throws IOException, ServletException { 37 | HttpServletResponse response = (HttpServletResponse) servletResponse; 38 | response.setHeader("Content-Security-Policy", "default-src 'self'; report-uri CSPReporting"); 39 | 40 | filterChain.doFilter(servletRequest, response); 41 | } 42 | 43 | @Override 44 | public void init(FilterConfig filterConfig) { 45 | } 46 | 47 | @Override 48 | public void destroy() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/CSPReportingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter checks any request for {@code reporting.jsp} by adding the {@code 27 | * Content-Security-Policy-Report-Only} header to the response. Violations are not blocked but reported to the {@see 28 | * CSPReporting} servlet. The {@code urlPatterns} should be far more wildcard in a real web application than in this 29 | * demo project. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | @WebFilter(filterName = "CSPReportingFilter", urlPatterns = {"/csp/reporting.jsp"}) 34 | public class CSPReportingFilter implements Filter { 35 | @Override 36 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 37 | FilterChain filterChain) throws IOException, ServletException { 38 | HttpServletResponse response = (HttpServletResponse) servletResponse; 39 | response.setHeader("Content-Security-Policy-Report-Only", "default-src 'self'; report-uri CSPReporting"); 40 | 41 | filterChain.doFilter(servletRequest, response); 42 | } 43 | 44 | @Override 45 | public void init(FilterConfig filterConfig) { 46 | } 47 | 48 | @Override 49 | public void destroy() { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/CacheControlFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code cache-control/protected.jsp} page against being cached by the user agent. The 27 | * {@code urlPatterns} should be far more wildcard in a real web application than in this demo project. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | @WebFilter(filterName = "CacheControlFilter", urlPatterns = {"/cache-control/protected.jsp", "/all/all.jsp"}) 32 | public class CacheControlFilter implements Filter { 33 | @Override 34 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 35 | FilterChain filterChain) throws IOException, ServletException { 36 | HttpServletResponse response = (HttpServletResponse) servletResponse; 37 | response.addHeader("Cache-Control", "no-cache, must-revalidate, max-age=0, no-store"); 38 | response.addDateHeader("Expires", -1); 39 | 40 | filterChain.doFilter(servletRequest, response); 41 | } 42 | 43 | @Override 44 | public void init(FilterConfig filterConfig) { 45 | } 46 | 47 | @Override 48 | public void destroy() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/HSTSFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the complete domain by forcing HTTPS usage. The url pattern does not have any influence 27 | * on this header. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | @WebFilter(filterName = "HSTSFilter", urlPatterns = {"/*"}) 32 | public class HSTSFilter implements Filter { 33 | @Override 34 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 35 | FilterChain filterChain) throws IOException, ServletException { 36 | HttpServletResponse response = (HttpServletResponse) servletResponse; 37 | response.addHeader("Strict-Transport-Security", "max-age=31556926; includeSubDomains"); 38 | 39 | filterChain.doFilter(servletRequest, response); 40 | } 41 | 42 | @Override 43 | public void init(FilterConfig filterConfig) { 44 | } 45 | 46 | @Override 47 | public void destroy() { 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/XContentTypeOptionsFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code x-content-type-options/protected.txt} against content sniffing attacks by 27 | * adding the {@code X-Content-Type-Options} header and the content type to the response. The {@code urlPatterns} should 28 | * be far more wildcard in a real web application than in this demo project, and the content type would be provided 29 | * individually, e.g. by a servlet. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | @WebFilter(filterName = "XContentTypeOptionsFilter", urlPatterns = {"/x-content-type-options/protected.txt", 34 | "/all/all.jsp"}) 35 | public class XContentTypeOptionsFilter implements Filter { 36 | @Override 37 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 38 | FilterChain filterChain) throws IOException, ServletException { 39 | HttpServletResponse response = (HttpServletResponse) servletResponse; 40 | response.setContentType("text/plain"); 41 | response.addHeader("X-Content-Type-Options", "nosniff"); 42 | 43 | filterChain.doFilter(servletRequest, response); 44 | } 45 | 46 | @Override 47 | public void init(FilterConfig filterConfig) { 48 | } 49 | 50 | @Override 51 | public void destroy() { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/XFrameOptionsFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code x-frame-options/protected.jsp} page against clickjacking by adding the {@code 27 | * X-Frame-Options} header to the response. The {@code urlPatterns} should be far more wildcard in a real web 28 | * application than in this demo project. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @WebFilter(filterName = "XFrameOptionsFilter", urlPatterns = {"/x-frame-options/protectedForm.jsp", "/all/all.jsp"}) 33 | public class XFrameOptionsFilter implements Filter { 34 | @Override 35 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 36 | FilterChain filterChain) throws IOException, ServletException { 37 | HttpServletResponse response = (HttpServletResponse) servletResponse; 38 | response.addHeader("X-Frame-Options", "DENY"); 39 | // response.addHeader("X-Frame-Options", "SAMEORIGIN"); 40 | // response.addHeader("X-Frame-Options", "ALLOW-FROM http://localhost:8080"); 41 | 42 | filterChain.doFilter(servletRequest, response); 43 | } 44 | 45 | @Override 46 | public void init(FilterConfig filterConfig) { 47 | } 48 | 49 | @Override 50 | public void destroy() { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/filter/XXSSProtectionFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.filter; 19 | 20 | import javax.servlet.*; 21 | import javax.servlet.annotation.WebFilter; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | 25 | /** 26 | * This servlet filter protects the {@code x-xss-protection/protected.jsp} page by adding the {@code X-XSS-Protection} 27 | * header to the response. The {@code urlPatterns} should be far more wildcard in a real web application than in this 28 | * demo project. 29 | * 30 | * @author Dominik Schadow 31 | */ 32 | @WebFilter(filterName = "XXSSProtectionFilter", urlPatterns = {"/x-xss-protection/protected.jsp", "/all/all.jsp"}) 33 | public class XXSSProtectionFilter implements Filter { 34 | @Override 35 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 36 | FilterChain filterChain) throws IOException, ServletException { 37 | HttpServletResponse response = (HttpServletResponse) servletResponse; 38 | response.setHeader("X-XSS-Protection", "1; mode=block"); 39 | 40 | filterChain.doFilter(servletRequest, response); 41 | } 42 | 43 | @Override 44 | public void init(FilterConfig filterConfig) { 45 | } 46 | 47 | @Override 48 | public void destroy() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/servlets/CSPReporting.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.servlets; 19 | 20 | import com.google.gson.*; 21 | 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | import java.io.BufferedReader; 27 | import java.io.IOException; 28 | import java.io.InputStreamReader; 29 | import java.io.Serial; 30 | import java.nio.charset.StandardCharsets; 31 | 32 | /** 33 | * Simple CSP-Reporting servlet to receive and print out any JSON style CSP report with violations. 34 | * 35 | * @author Dominik Schadow 36 | */ 37 | @WebServlet(name = "CSPReporting", urlPatterns = {"/csp/CSPReporting"}) 38 | public class CSPReporting extends HttpServlet { 39 | @Serial 40 | private static final long serialVersionUID = 5150026442855960085L; 41 | private static final System.Logger LOG = System.getLogger(CSPReporting.class.getName()); 42 | 43 | @Override 44 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 45 | try (InputStreamReader isr = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr)) { 46 | Gson gs = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); 47 | JsonElement element = JsonParser.parseReader(reader); 48 | 49 | LOG.log(System.Logger.Level.INFO, "\n{}", gs.toJson(element)); 50 | } catch (IOException | JsonSyntaxException ex) { 51 | LOG.log(System.Logger.Level.ERROR, ex.getMessage(), ex); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/servlets/FakeServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.servlets; 19 | 20 | import javax.servlet.annotation.WebServlet; 21 | import javax.servlet.http.HttpServlet; 22 | import javax.servlet.http.HttpServletRequest; 23 | import javax.servlet.http.HttpServletResponse; 24 | import java.io.IOException; 25 | import java.io.PrintWriter; 26 | import java.io.Serial; 27 | 28 | /** 29 | * Fake login servlet which returns a success message. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | @WebServlet(name = "FakeServlet", urlPatterns = {"/x-frame-options/FakeServlet", "/csp2/FakeServlet"}) 34 | public class FakeServlet extends HttpServlet { 35 | @Serial 36 | private static final long serialVersionUID = -6474742244481023685L; 37 | private static final System.Logger LOG = System.getLogger(FakeServlet.class.getName()); 38 | 39 | @Override 40 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 41 | LOG.log(System.Logger.Level.INFO, "Processing fake request..."); 42 | 43 | response.setContentType("text/html; charset=UTF-8"); 44 | 45 | try (PrintWriter out = response.getWriter()) { 46 | out.println(""); 47 | out.println(""); 48 | out.println(""); 49 | out.println("Security Response Header"); 50 | out.println(""); 51 | out.println(""); 52 | out.println("

Fake login successful

"); 53 | out.println("
Home
"); 54 | out.println(""); 55 | out.println(""); 56 | } catch (IOException ex) { 57 | LOG.log(System.Logger.Level.ERROR, ex.getMessage(), ex); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /security-header/src/main/java/de/dominikschadow/javasecurity/header/servlets/LoginServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.header.servlets; 19 | 20 | import javax.servlet.annotation.WebServlet; 21 | import javax.servlet.http.HttpServlet; 22 | import javax.servlet.http.HttpServletRequest; 23 | import javax.servlet.http.HttpServletResponse; 24 | import java.io.IOException; 25 | import java.io.PrintWriter; 26 | import java.io.Serial; 27 | 28 | /** 29 | * Simple login servlet which returns a success message. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | @WebServlet(name = "LoginServlet", urlPatterns = {"/x-frame-options/LoginServlet", "/cache-control/LoginServlet", 34 | "/csp2/LoginServlet"}) 35 | public class LoginServlet extends HttpServlet { 36 | @Serial 37 | private static final long serialVersionUID = -660893987741671511L; 38 | private static final System.Logger LOG = System.getLogger(LoginServlet.class.getName()); 39 | 40 | @Override 41 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 42 | LOG.log(System.Logger.Level.INFO, "Processing login request..."); 43 | 44 | response.setContentType("text/html; charset=UTF-8"); 45 | 46 | try (PrintWriter out = response.getWriter()) { 47 | out.println(""); 48 | out.println(""); 49 | out.println(""); 50 | out.println("Security Response Header"); 51 | out.println(""); 52 | out.println(""); 53 | out.println("

Login successful

"); 54 | out.println("
Home
"); 55 | out.println(""); 56 | out.println(""); 57 | } catch (IOException ex) { 58 | LOG.log(System.Logger.Level.ERROR, ex.getMessage(), ex); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | Java-Security-Header 7 | 8 | 9 | index.jsp 10 | 11 | 12 | 13 | 30 14 | 15 | true 16 | 17 | COOKIE 18 | 19 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/all/all.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | All Header and Meta Tags 9 | 10 | 11 |

All Header and Meta Tags

12 |
Home
13 | 14 | 15 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/cache-control/protected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Cache-Control: Protected 7 | 8 | 9 |

Cache-Control: Protected

10 | 11 |
12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |
23 | 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/cache-control/unprotected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Cache-Control: Unprotected 7 | 8 | 9 |

Cache-Control: Unprotected

10 | 11 |
12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |
23 | 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp/protected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | Content Security Policy: Protected 5 | 6 | 7 | 8 |

Content Security Policy: Protected

9 | 10 |
Name <%= request.getParameter("name") %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp/reporting.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | Content Security Policy: Report-Only 5 | 6 | 7 | 8 |

Content Security Policy: Report-Only

9 | 10 |
Name <%= request.getParameter("name") %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp/unprotected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | Content Security Policy: Unprotected 5 | 6 | 7 | 8 |

Content Security Policy: Unprotected

9 | 10 |
Name <%= request.getParameter("name") %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp2/protected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | Content Security Policy Level 2: Protected 5 | 6 | 7 | 9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp2/protectedForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Protected Form 7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp2/unprotected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | Content Security Policy Level 2: Unprotected 5 | 6 | 7 | 9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/csp2/unprotectedForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Unprotected Form 7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> 2 | 3 | 4 | 5 | 6 | 7 | Security Header 8 | 9 | 10 |

Security Header

11 | 12 |

Each response header can be called in an unprotected and in a protected version. Every header is added by a 13 | filter. There are no special pages for HSTS since this header is only active or inactive for the whole domain. 14 | Content Security Policy and especially Content Security Policy Level 2 and Level 3 may not work in your browser at 15 | all, other headers may vary (a little) depending on the selected browser.

16 | 17 |

X-Content-Type-Options

18 | 19 |

20 | Unprotected | 21 | Protected 22 |

23 | 24 |

Cache-Control

25 | 26 |

27 | Unprotected | 28 | Protected 29 |

30 | 31 |

X-Frame-Options

32 | 33 |

34 | Original Form | 35 | Unprotected | 36 | Protected 37 |

38 | 39 |

Content Security Policy Level 1

40 | 41 |

42 | Unprotected | 43 | Protected | 44 | Report Only 45 |

46 | 47 |

Content Security Policy Level 2

48 | 49 |

50 | Original Form | 51 | Unprotected | 52 | Protected 53 |

54 | 55 |

X-XSS-Protection

56 | 57 |

58 | Unprotected | 59 | Protected 60 |

61 | 62 |

All Header and Meta Tags

63 | 64 |

65 | Protected 66 |

67 | 68 | 69 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/resources/css/styles.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 2em; 3 | } 4 | 5 | h2 { 6 | font-size: 1.7em; 7 | } 8 | 9 | p { 10 | font-size: 1.5em; 11 | } 12 | 13 | a { 14 | color: darkblue; 15 | } 16 | 17 | input { 18 | display: inline-block; 19 | vertical-align: middle; 20 | margin-top: 2em; 21 | width: 150px; 22 | } 23 | 24 | input[type=submit] { 25 | margin: 2em 0 0 25em; 26 | width: 75px; 27 | height: 20px; 28 | } 29 | 30 | label { 31 | text-align: right; 32 | display: inline-block; 33 | vertical-align: middle; 34 | width: 10em; 35 | margin: 1em 1em 0 0; 36 | } 37 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-content-type-options/protected.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | This page should not be rendered as HTML. 4 | 5 | 6 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-content-type-options/unprotected.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | This page should not be rendered as HTML. 4 | 5 | 6 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-frame-options/protected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | X-Frame-Options: Protected 5 | 6 | 7 | 9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-frame-options/protectedForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Protected Form 7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-frame-options/unprotected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | X-Frame-Options: Unprotected 5 | 6 | 7 | 9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-frame-options/unprotectedForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | Unprotected Form 7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-xss-protection/protected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | X-XSS-Protection: Protected 5 | 6 | 7 | 8 |

X-XSS-Protection: Protected

9 | 10 |
Name <%= request.getParameter("name") %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /security-header/src/main/webapp/x-xss-protection/unprotected.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | X-XSS-Protection: Unprotected 5 | 6 | 7 | 8 |

X-XSS-Protection: Unprotected

9 | 10 |
Name <%= request.getParameter("name") %>
11 | 12 | 13 | -------------------------------------------------------------------------------- /security-logging/src/main/java/de/dominikschadow/javasecurity/logging/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.logging; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | /** 24 | * Starter class for the Spring Boot application. 25 | * 26 | * @author Dominik Schadow 27 | */ 28 | @SpringBootApplication 29 | public class Application { 30 | public static void main(String[] args) { 31 | SpringApplication.run(Application.class, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /security-logging/src/main/java/de/dominikschadow/javasecurity/logging/home/Login.java: -------------------------------------------------------------------------------- 1 | package de.dominikschadow.javasecurity.logging.home; 2 | 3 | public record Login(String username, String password) { 4 | } 5 | -------------------------------------------------------------------------------- /security-logging/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36}: [%marker] - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /security-logging/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Security Logging 9 | 10 | 11 |
12 |
13 |
14 |

Security Logging

15 |

This demo application demonstrates the usage of the OWASP Security Logging library.

16 |
17 |
18 | 19 |
20 |
21 |

Login

22 |

Use any data to log in and have a look at the console for security relevant logging messages 23 | afterwards.

24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /security-logging/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Security Logging 9 | 10 | 11 |
12 |
13 |
14 |

Security Logging

15 |

Have a look at the console for logging details.

16 | 17 |

Home

18 |
19 |
20 |
21 | 22 | -------------------------------------------------------------------------------- /security-logging/src/test/java/de/dominikschadow/javasecurity/logging/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.logging; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /serialize-me/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | serialize-me 12 | jar 13 | Serialize Me 14 | 15 | Java serialization sample project. User the main method to get started. 16 | 17 | 18 | 19 | com.google.guava 20 | guava 21 | 22 | 23 | -------------------------------------------------------------------------------- /serialize-me/src/main/java/de/dominikschadow/javasecurity/serialize/Deserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.serialize; 19 | 20 | import java.io.BufferedInputStream; 21 | import java.io.FileInputStream; 22 | import java.io.ObjectInputStream; 23 | 24 | public class Deserializer { 25 | public static void main(String[] args) { 26 | try (ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(new FileInputStream("serialize-me.bin")))) { 27 | SerializeMe me = (SerializeMe) is.readObject(); 28 | 29 | System.out.println("I am " + me.getFirstname() + " " + me.getLastname()); 30 | } catch (Exception ex) { 31 | ex.printStackTrace(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /serialize-me/src/main/java/de/dominikschadow/javasecurity/serialize/SerializeMe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.serialize; 19 | 20 | import java.io.Serial; 21 | import java.io.Serializable; 22 | 23 | public class SerializeMe implements Serializable { 24 | @Serial 25 | private static final long serialVersionUID = 4811291877894678577L; 26 | private String firstname; 27 | private String lastname; 28 | 29 | public String getFirstname() { 30 | return firstname; 31 | } 32 | 33 | public void setFirstname(String firstname) { 34 | this.firstname = firstname; 35 | } 36 | 37 | public String getLastname() { 38 | return lastname; 39 | } 40 | 41 | public void setLastname(String lastname) { 42 | this.lastname = lastname; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /serialize-me/src/main/java/de/dominikschadow/javasecurity/serialize/Serializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.serialize; 19 | 20 | import java.io.FileOutputStream; 21 | import java.io.ObjectOutputStream; 22 | 23 | public class Serializer { 24 | public static void main(String[] args) { 25 | SerializeMe serializeMe = new SerializeMe(); 26 | serializeMe.setFirstname("Arthur"); 27 | serializeMe.setLastname("Dent"); 28 | 29 | try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize-me.bin"))) { 30 | oos.writeObject(serializeMe); 31 | oos.flush(); 32 | } catch (Exception ex) { 33 | ex.printStackTrace(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/java/de/dominikschadow/javasecurity/sessionhandling/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.sessionhandling; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 23 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 24 | 25 | /** 26 | * Starter class for the Spring Boot application. 27 | * 28 | * @author Dominik Schadow 29 | */ 30 | @SpringBootApplication 31 | @EnableWebSecurity 32 | public class Application implements WebMvcConfigurer { 33 | public static void main(String[] args) { 34 | SpringApplication.run(Application.class, args); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/java/de/dominikschadow/javasecurity/sessionhandling/greetings/GreetingController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.sessionhandling.greetings; 19 | 20 | import jakarta.servlet.http.HttpSession; 21 | import lombok.RequiredArgsConstructor; 22 | import org.springframework.stereotype.Controller; 23 | import org.springframework.ui.Model; 24 | import org.springframework.web.bind.annotation.GetMapping; 25 | 26 | /** 27 | * Greeting controller to return the user/ admin greeting to the caller. 28 | * 29 | * @author Dominik Schadow 30 | */ 31 | @Controller 32 | @RequiredArgsConstructor 33 | public class GreetingController { 34 | private final GreetingService greetingService; 35 | 36 | @GetMapping("/") 37 | public String index(Model model, HttpSession session) { 38 | model.addAttribute("sessionId", session.getId()); 39 | 40 | return "index"; 41 | } 42 | 43 | @GetMapping("user/user") 44 | public String greetUser(Model model, HttpSession session) { 45 | model.addAttribute("sessionId", session.getId()); 46 | model.addAttribute("greeting", greetingService.greetUser()); 47 | 48 | return "user/user"; 49 | } 50 | 51 | @GetMapping("admin/admin") 52 | public String greetAdmin(Model model, HttpSession session) { 53 | model.addAttribute("sessionId", session.getId()); 54 | model.addAttribute("greeting", greetingService.greetAdmin()); 55 | 56 | return "admin/admin"; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/java/de/dominikschadow/javasecurity/sessionhandling/greetings/GreetingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.sessionhandling.greetings; 19 | 20 | import org.springframework.security.access.prepost.PreAuthorize; 21 | import org.springframework.stereotype.Service; 22 | 23 | /** 24 | * GreetingService implementation to return some hardcoded greetings. 25 | * 26 | * @author Dominik Schadow 27 | */ 28 | @Service 29 | public class GreetingService { 30 | @PreAuthorize("hasAnyRole('USER','ADMIN')") 31 | public String greetUser() { 32 | return "Spring Security says hello to the user!"; 33 | } 34 | 35 | @PreAuthorize("hasRole('ADMIN')") 36 | public String greetAdmin() { 37 | return "Spring Security says hello to the admin!"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | main: 3 | web-application-type: servlet 4 | datasource: 5 | username: sa 6 | password: sa 7 | name: session-handling 8 | generate-unique-name: false 9 | h2: 10 | console: 11 | enabled: true 12 | jpa: 13 | hibernate: 14 | ddl-auto: none -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/resources/templates/admin/admin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Session Handling - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

User Profile 15 | 16 |

17 | 18 |

Your current session is 19 | and you are not logged in.

20 |

Your current session is 21 | and you are logged in as .

22 |
23 |
24 | 25 | 30 | 31 |
32 |
33 | Logout 34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Session Handling - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

Session Handling - Spring Security

15 | 16 |

Your current session is 17 | and you are not logged in.

18 |

Your current session is 19 | and you are logged in as .

20 |
21 |
22 | 23 | 31 | 32 |
33 |
34 | Logout 35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/main/resources/templates/user/user.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Session Handling - Spring Security 9 | 10 | 11 |
12 |
13 |
14 |

User Profile 15 | 16 |

17 | 18 |

Your current session is 19 | and you are not logged in.

20 |

Your current session is 21 | and you are logged in as .

22 |
23 |
24 | 25 | 30 | 31 |
32 |
33 | Logout 34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /session-handling-spring-security/src/test/java/de/dominikschadow/javasecurity/sessionhandling/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.sessionhandling; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /session-handling/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | session-handling 12 | war 13 | Session Handling 14 | 15 | Session Handling sample project. Requires a server like Apache Tomcat 8 (with Servlet 3.1 support) 16 | or the Maven Jetty plugin. After launching, open the web application in your browser at 17 | http://localhost:8080/session-handling 18 | 19 | 20 | 21 | 22 | javax.servlet 23 | javax.servlet-api 24 | 25 | 26 | 27 | 28 | jetty:run-war 29 | 30 | 31 | org.eclipse.jetty 32 | jetty-maven-plugin 33 | 34 | 35 | /session-handling 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /session-handling/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Session Handling 7 | 8 | 9 |

Session Handling

10 | 11 |

Use any data to (fake) login.

12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /session-handling/src/main/webapp/resources/css/styles.css: -------------------------------------------------------------------------------- 1 | .text-input { 2 | width: 250px; 3 | } 4 | 5 | h1 { 6 | font-size: 150%; 7 | } 8 | 9 | h2 { 10 | font-size: 125%; 11 | } 12 | 13 | td { 14 | font-size: 115%; 15 | } 16 | 17 | th { 18 | background-color: darkgrey; 19 | padding: 2pt; 20 | font-weight: bold; 21 | font-size: 125%; 22 | } 23 | -------------------------------------------------------------------------------- /sql-injection/src/main/java/de/dominikschadow/javasecurity/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | /** 24 | * Starter class for the Spring Boot application. 25 | * 26 | * @author Dominik Schadow 27 | */ 28 | @SpringBootApplication 29 | public class Application { 30 | public static void main(String[] args) { 31 | SpringApplication.run(Application.class, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sql-injection/src/main/java/de/dominikschadow/javasecurity/customers/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.customers; 19 | 20 | import jakarta.persistence.Entity; 21 | import jakarta.persistence.Id; 22 | import jakarta.persistence.Table; 23 | import lombok.Getter; 24 | import lombok.Setter; 25 | 26 | @Entity 27 | @Table(name = "customers") 28 | @Getter 29 | @Setter 30 | public class Customer { 31 | @Id 32 | private Integer id; 33 | private String name; 34 | private String status; 35 | private int orderLimit; 36 | 37 | @Override 38 | public String toString() { 39 | return "ID " + id + ", Name " + name + ", Status " + status + ", Order Limit " + orderLimit; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sql-injection/src/main/resources/ESAPI.properties: -------------------------------------------------------------------------------- 1 | # Logging 2 | Logger.ApplicationName=SQL-Injection 3 | Logger.LogEncodingRequired=false 4 | Logger.UserInfo=false 5 | Logger.ClientInfo=false 6 | Logger.LogApplicationName=true 7 | Logger.LogServerIP=false -------------------------------------------------------------------------------- /sql-injection/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | username: sa 4 | password: sa 5 | name: sql-injection 6 | generate-unique-name: false 7 | h2: 8 | console: 9 | enabled: true 10 | jpa: 11 | hibernate: 12 | ddl-auto: none -------------------------------------------------------------------------------- /sql-injection/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO customers (id, name, status, order_limit) VALUES (1, 'Arthur Dent', 'A', 10000); 2 | INSERT INTO customers (id, name, status, order_limit) VALUES (2, 'Ford Prefect', 'B', 5000); 3 | INSERT INTO customers (id, name, status, order_limit) VALUES (3, 'Tricia Trillian McMillan', 'C', 1000); 4 | INSERT INTO customers (id, name, status, order_limit) VALUES (4, 'Zaphod Beeblebrox', 'D', 500); 5 | INSERT INTO customers (id, name, status, order_limit) VALUES (5, 'Marvin', 'A', 100000); 6 | INSERT INTO customers (id, name, status, order_limit) VALUES (6, 'Slartibartfast', 'D', 100); -------------------------------------------------------------------------------- /sql-injection/src/main/resources/esapi-java-logging.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dschadow/JavaSecurity/b37ac2f02d1586d19be0f1dad52ce7f335fdb18c/sql-injection/src/main/resources/esapi-java-logging.properties -------------------------------------------------------------------------------- /sql-injection/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE customers 2 | ( 3 | id INTEGER NOT NULL, 4 | name VARCHAR(50) NOT NULL, 5 | status VARCHAR(50), 6 | order_limit INTEGER NOT NULL, 7 | PRIMARY KEY (id) 8 | ); -------------------------------------------------------------------------------- /sql-injection/src/main/resources/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | SQL Injection 9 | 10 | 11 |
12 |
13 |
14 |

SQL Injection

15 |
16 |
17 | 18 |
19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
IDNameStatusOrder Limit
39 |
40 |
41 |
42 | 43 |
44 |
45 | Try again 46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /sql-injection/src/test/java/de/dominikschadow/javasecurity/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity; 19 | 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class ApplicationTest { 25 | @Test 26 | public void contextLoads() { 27 | } 28 | } -------------------------------------------------------------------------------- /xss/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | de.dominikschadow.javasecurity 7 | javasecurity 8 | 4.0.0 9 | 10 | 4.0.0 11 | xss 12 | war 13 | Cross-Site Scripting 14 | 15 | Cross-Site Scripting (XSS) sample project. Requires a server like Apache Tomcat or the Maven Tomcat7 16 | plugin. After launching, open the web application in your browser at http://localhost:8080/xss 17 | 18 | 19 | 20 | 21 | org.owasp.encoder 22 | encoder 23 | 24 | 25 | org.owasp.encoder 26 | encoder-jsp 27 | 28 | 29 | javax.servlet 30 | javax.servlet-api 31 | 32 | 33 | 34 | 35 | tomcat7:run-war 36 | 37 | 38 | org.apache.tomcat.maven 39 | tomcat7-maven-plugin 40 | 41 | 42 | ${project.basedir}/src/main/resources/context.xml 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /xss/src/main/java/de/dominikschadow/javasecurity/xss/InputValidatedServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Dominik Schadow, dominikschadow@gmail.com 3 | * 4 | * This file is part of the Java Security project. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package de.dominikschadow.javasecurity.xss; 19 | 20 | import javax.servlet.annotation.WebServlet; 21 | import javax.servlet.http.HttpServlet; 22 | import javax.servlet.http.HttpServletRequest; 23 | import javax.servlet.http.HttpServletResponse; 24 | import java.io.IOException; 25 | import java.io.PrintWriter; 26 | import java.io.Serial; 27 | 28 | /** 29 | * Servlet expecting validated input from the frontend. 30 | * 31 | * @author Dominik Schadow 32 | */ 33 | @WebServlet(name = "InputValidatedServlet", urlPatterns = {"/validated"}) 34 | public class InputValidatedServlet extends HttpServlet { 35 | @Serial 36 | private static final long serialVersionUID = -3167797061670620847L; 37 | private static final System.Logger LOG = System.getLogger(InputValidatedServlet.class.getName()); 38 | 39 | @Override 40 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 41 | String name = request.getParameter("inputValidatedName"); 42 | 43 | LOG.log(System.Logger.Level.INFO, "Received {0} as name", name); 44 | 45 | response.setContentType("text/html"); 46 | 47 | try (PrintWriter out = response.getWriter()) { 48 | out.println(""); 49 | out.println("Cross-Site Scripting (XSS) - Input Validation"); 50 | out.println(""); 51 | out.println(""); 52 | out.println(""); 53 | out.println("

Cross-Site Scripting (XSS) - Input Validation

"); 54 | out.println("

[" + name + "]

"); 55 | out.println("

Home

"); 56 | out.println(""); 57 | } catch (IOException ex) { 58 | LOG.log(System.Logger.Level.ERROR, ex.getMessage(), ex); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /xss/src/main/resources/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /xss/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | XSS 7 | 8 | 9 | index.jsp 10 | 11 | 12 | 13 | 30 14 | 15 | 16 | false 17 | 18 | COOKIE 19 | 20 | -------------------------------------------------------------------------------- /xss/src/main/webapp/alert.js: -------------------------------------------------------------------------------- 1 | alert("XSS from JS file"); -------------------------------------------------------------------------------- /xss/src/main/webapp/escaped.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="e" uri="https://www.owasp.org/index.php/OWASP_Java_Encoder_Project" %> 2 | <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | 8 | Cross-Site Scripting (XSS) - JSP Output Escaping 9 | 10 | 11 |

Cross-Site Scripting (XSS) - JSP Output Escaping

12 | 13 |

For HTML

14 | 15 |

For CSS

16 | 17 |

For XML

18 | 19 |

Home

20 | 21 | 22 | -------------------------------------------------------------------------------- /xss/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cross-Site Scripting (XSS) 7 | 8 | 9 |

Cross-Site Scripting (XSS)

10 | 11 |

Instructions

12 | 13 |

Enter some attack data to show the user's session id in an alert box. You will not be successful with every form. 14 | Can you explain why? Can you secure the validated form (With Input Validation) with output escaping 15 | and the Context Security Policy?

16 | 17 |
18 |
19 | Unprotected 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | With Input Validation 29 | 30 | 31 | 32 |
33 |
34 | 35 |
36 |
37 | With Output Escaping 38 | 39 | 40 | 41 |
42 |
43 | 44 |
45 |
46 | With JSP Output Escaping 47 | 48 | 49 | 50 |
51 |
52 | 53 |
54 |
55 | With Content Security Policy (CSP) 56 | 57 | 58 | 59 |
60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /xss/src/main/webapp/resources/css/styles.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 1.5em; 3 | } 4 | 5 | h2 { 6 | font-size: 1.2em; 7 | } 8 | 9 | a { 10 | color: darkblue; 11 | } 12 | 13 | fieldset { 14 | width: 500px; 15 | margin-top: 20px; 16 | } 17 | 18 | input { 19 | display: inline-block; 20 | vertical-align: middle; 21 | width: 250px; 22 | } 23 | 24 | input[type=submit] { 25 | width: 75px; 26 | height: 20px; 27 | margin-left: 10px; 28 | } 29 | 30 | label { 31 | margin-right: 10px; 32 | } 33 | --------------------------------------------------------------------------------