Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

JavaFest. Nanne Baars. Web application security for developers

26 vues

Publié le

Security is an important topic for developers however security is often an afterthought in a project. This presentation will focus on practices which developers need to be aware of, and make security fun again. This is an in depth talk about 10 topics not an overview for security best practices.

Publié dans : Formation
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

JavaFest. Nanne Baars. Web application security for developers

  1. 1. SECURITY FOR DEVELOPERS Nanne Baars
  2. 2. About me ¨ Java developer ¨ Developer à Security consultant à Developer ¨ Project lead of WebGoat à https://github.com/WebGoat/
  3. 3. WebGoat is… ¨ A deliberately vulnerable web application maintained by OWASP designed to teach web application security lessons. ¨ In each lesson, users must demonstrate their understanding of a security issue by exploiting a real vulnerability in the WebGoat application
  4. 4. https://webgoat.github.io/WebGoat/ Learn in 3 steps
  5. 5. - Examples - Background - How to prevent
  6. 6. https://www.pentestpartners.com/security-blog/hacking-ski-helmet-audio/
  7. 7. https://www.pentestpartners.com/security-blog/hacking-ski-helmet-audio/
  8. 8. Secret management
  9. 9. Still a problem https://darkport.co.uk/blog/ahh-shhgit!/
  10. 10. https://darkport.co.uk/blog/ahh-shhgit!/
  11. 11. https://blog.milessteele.com/posts/2013-07-07-hiding-djangos-secret-key.html
  12. 12. Within projects as developers… ¨ Make sure secrets do not end up in Git ¤ Encrypt your secrets (for example like Travis CI) ¤ More fancy use Vault, KeyCloak etc ¨ Use tooling to scan your repository ¨ Define a policy what should be done in case it happens ¤ Git history
  13. 13. As a team… ¨ Think about what to do when a team member leaves… ¤ Think about how many systems you have access to, is the access to AWS, Kubernetes, Github, Gitlab, Jira etc centrally provided? ¨ Again, have a clear policy in place
  14. 14. Easy to automate
  15. 15. Cryptography
  16. 16. private static final byte[] ENCRYPT_IV = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; public static String encrypt(String dataPassword, String cleartext) throws Exception { IvParameterSpec zeroIv = new IvParameterSpec(ENCRYPT_IV); SecretKeySpec key = new SecretKeySpec(dataPassword.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv); … } private static final byte[] ENCRYPT_IV = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; public static String encrypt(String dataPassword, String cleartext) throws Exception { IvParameterSpec zeroIv = new IvParameterSpec(ENCRYPT_IV); SecretKeySpec key = new SecretKeySpec(dataPassword.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv); … }
  17. 17. Cryptography vs developers
  18. 18. “In this post I will show you how to use RSA in Java…..” public static String encrypt(String plainText, PublicKey publicKey) { Cipher encryptCipher = Cipher.getInstance("RSA"); encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(UTF_8)); return Base64.getEncoder().encodeToString(cipherText); }
  19. 19. public static void main(String [] args) throws Exception { // generate public and private keys … // sign the message byte [] signed = encrypt(privateKey, "This is a secret message"); System.out.println(new String(signed)); // <<signed message>> // verify the message byte[] verified = decrypt(pubKey, encrypted); System.out.println(new String(verified)); // This is a secret message } public static byte[] encrypt(PrivateKey privateKey, String message) { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(message.getBytes()); } public static byte[] decrypt(PublicKey publicKey, byte [] encrypted) { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(encrypted); }
  20. 20. Solution - Libsodium or Google Tink
  21. 21. https://github.com/google/tink
  22. 22. Path traversal ¨ A path(directory) traversal is a vulnerability where an attacker is able to access or store files and directories outside the location where the application is running. ¨ For example: http://example.com/file=report.pdf ¨ Change into: http://example.com/file=../../../../../etc/passwd ¨ In case of a file upload you might be able to overwrite other files
  23. 23. https://hackerone.com/reports/827052
  24. 24. https://snyk.io/research/zip-slip-vulnerability
  25. 25. Mitigation in file upload var multiPartFile = ... var targetFile = new File("/tmp", multiPartFile.getOriginalName()); var canonicalPath = targetFile.getCanonicalPath(); if (!canonicalPath.startWith("/tmp") { throw new IllegalArgumentException("Invalid filename"); } IOUtils.copy(multiPartFile.getBytes(), targetFile);
  26. 26. Input validation ¨ Check for ../ ¨ Be aware of encoding: %2e%2e/%2f ¨ Spring Security has: StrictHttpFirewall which automatically drops a request if the path variable contains ../
  27. 27. @Getter("/f") public void f(@RequestParam("name") String name) { //name is automatically decoded so %2E%2E%2F%2E%2E%2Ftest //will become ../../test } @Getter("/g") public void g(HttpServletRequest request) { var queryString = request.getQueryString(); // will return %2E%2E%2F%2E%2E%2Ftest } @Getter("/h") public void h(HttpServletRequest request) { var name = request.getParam("name"); //will return ../../test
  28. 28. Host-Header Injection ¨ In web applications, developers use the HTTP Host header available in HTTP request ¨ A remote attacker can exploit this by sending a fake header with a domain name under the attackers control.
  29. 29. Often found during password reset curl 'https://webgoat-cloud.net/create-password-reset-link' --data-raw 'email=test1234@webgoat-cloud.net'
  30. 30. Let’s do that again… curl 'http://webgoat-cloud.net/create-password-reset-link' -H'Host: attacker.com' --data-raw 'email=test1234@webgoat.org'
  31. 31. Example 2: Azure Authentication / Spring Boot Example.com
  32. 32. Easy to setup ¨ Standard Spring Boot / Azure auto configuration provided 1. Register your application with your Azure Active Directory Tenant 2. Configure application.properties spring.security.oauth2.client.registration.azure.client-id=xxxxxx-your-client-id-xxxxxx spring.security.oauth2.client.registration.azure.client-secret=xxxxxx-your-client-secret-xxxxxx azure.activedirectory.tenant-id=xxxxxx-your-tenant-id-xxxxxx azure.activedirectory.active-directory-groups=group1, group2
  33. 33. Spring Boot configuration ¨ We enabled this setting in the application.properties: server.use-forward-headers=true
  34. 34. curl -i http://localhost:8080 HTTP/1.1 302 Found Location: http://localhost:8080/oauth2/authorization/azure curl -i http://localhost:8080/oauth2/authorization/azure HTTP/1.1 302 Found Location: https://login.microsoftonline.com/common/oauth2/authorize?response_type=code https://graph.microsoft.com/user.read&state=& redirect_uri=http://localhost:8080/login/oauth2/code/azure
  35. 35. Now let’s try curl -i -H"X-Forwarded-Host: attacker.com" http://localhost:8080/ HTTP/1.1 302 Found Location: http://attacker.com/oauth2/authorization/azure
  36. 36. But wait how does the redirect_uri work? curl -i http://localhost:8080/oauth2/authorization/azure HTTP/1.1 302 Found Location: https://login.microsoftonline.com/common/oauth2/authorize?response_type=codehttps://graph. microsoft.com/user.read&state=&redirect_uri=http://localhost:8080/login/oauth2/code/azure spring.security.oauth2.client.registration.azure.redirect-uri-template={baseUrl}/login/oauth2/code/{registrationId}
  37. 37. curl -i -H"X-Forwarded-Host: attacker.com" http://localhost:8080/oauth2/authorization/azure HTTP/1.1 302 Found Location: https://login.microsoftonline.com/common/oauth2/authorize?response_type=code https://graph.microsoft.com/user.read&state=& redirect_uri=http://attacker.com/login/oauth2/code/azure
  38. 38. (Un)fortunately this does not work J https://tools.ietf.org/html/rfc6749#section-10.6
  39. 39. Recap ¨ This is not a bug in Spring security ¨ Something which happened because we added: server.use-forward-headers=true
  40. 40. Solution /** * <p> * Determines which hostnames should be allowed. The default is to allow any * hostname. * </p> * * @param allowedHostnames the predicate for testing hostnames * @since 5.2 */ public void setAllowedHostnames(Predicate<String> allowedHostnames) { if (allowedHostnames == null) { throw new IllegalArgumentException("allowedHostnames cannot be null"); } this.allowedHostnames = allowedHostnames; }
  41. 41. @Bean public HttpFirewall firewall() { StrictHttpFirewall firewall = new StrictHttpFirewall(); firewall.setAllowedHttpMethods(Arrays.asList("GET", "POST")); firewall.setAllowedHostnames(s -> s.equals("localhost")); curl -i -H"X-Forwarded-Host: attacker.com" http://localhost:8080/ java.lang.RuntimeException: org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the domain attacker.com is untrusted. at io.undertow.servlet.spec.RequestDispatcherImpl.error(RequestDispatcherImpl.java:507) at io.undertow.servlet.spec.RequestDispatcherImpl.error(RequestDispatcherImpl.java:427)
  42. 42. Solution ¨ As developers we are responsible to validate those headers ¨ Verify all headers you can receive from the outside. ¤ This includes: X-Forwarded-For, X-Forwarded-Host etc ¨ Do not rely on thinking reversed proxy will solve this! ¨ Check to see whether the framework has built in protection
  43. 43. Where to start... 1. Make developers security aware n Code review n Practice / learn / adapt 2. Adopt a security guideline in your team 3. Test your own application 4. Start using tools to find to most obvious mistakes

×