Real World Java Security

Tags: #<Tag:0x00007f8a17068170> #<Tag:0x00007f8a170680a8> #<Tag:0x00007f8a1706ad58> #<Tag:0x00007f8a17067e28> #<Tag:0x00007f8a17067d60>

This is my personal knowledge-base about Java software development with an opinionated emphasis on secure software design, coding, and analysis.

After reading this you will:

  • understand the security impact of underlying Java tech like Containers, Beans, Servlets…You’ll be able to talk to software developers, engineers, and architects. And how security professionals understand these technologies.
  • connect defensive coding techniques to distributed enterprise architecture approaches like Micro-Service design. - Exactly where many other Application Security articles fall short.
  • realize that all (ode-auditing tools have shortcomings and that integrating them in Continuous Integration and Deployment (CI / CD) is not the solution.

You don’t need to be an expert on any of these topics, but you’ll understand them in a (Java) development-centric context:

  • Application Security backgrounds, summed up for (Java) development:
    • CMU’s SEI CERT Oracle Coding Standard for Java
    • the OWASP (Top 10 + n) list
    • MITRE’s CWEs and ATT&CK
    • Threat Modeling approaches based on PASTA and Trike

This is not a secure coidng Wiki :slight_smile:

But to be clear: different kinds of vulnerabilities like

  • integer overflows,
  • Out-Of-Memory expansion bugs,
  • Denial of Service Vulnerabilities,
  • Use after Free bugs,
  • Out-Of-Bounds issues,

etc. can still be found and sometimes exploited to achieve remote code execution (RCE) in Java.


Real World Secure Design, Coding, and Analysis - by example with Java

Pseudo-code included!

lol

Isn't Java secure by design?

You heard that, too. Didn’t you…

Securing systems and applications these days is a difficult job, sometimes a technical one, but too often a political one.

The following paragraph focuses on:

  • notes on Java (the ecosystem and programming language) with the Java Virtual Machine (JVM) [1].
  • technical Runtime Security (Java Virtual Machine security) - how Java ensures code is safe to run

Too often Devs mix up two things:

  1. the security of business logic within enterprise applications
  2. the security of code and technical routines within a system like “the JVM”

To allow a structured analysis here is a very short definition of “the JVM”, which is the underlying runtime system (2).

The Java Virtual Machine

The JVM is a portable Bytecode[2] interpreter. There are different JVMs[3].

  1. the OpenJDK project Open Source JVM is called HotSpot, same like Oracle’s HotSpot. Both JVMs are 99% identical to each other.
  2. there is Graal (CE), which you should look at if you like being ahead / of the curve / of Time.
  3. IBM OpenJ9

Side note: Hotspots are parts of the compiled Java Bytecode that get frequently executed. They get translated into native code. More on that below.


tl;dr Java is a programming language. Commonly it gets translated to Bytecode, which runs within a JVM. There are different JVMs, which can be compliant to the JVM specification. These JVMs may have been designed with security in mind, but nothing is secure by design these days.

Not everything that says “Java” runs in a JVM. You can compile Java to anything you want. Even to C#[4].

The JVM specification defines a Stack-based virtual machine that interprets Bytecode (.class files).


Extra References
References

Note that the Android Runtime (ART) does not execute Bytecode just-in-time. It is not a JVM.

Android used to run Apps within Dalvik, which was not a JVM because it wasn’t Stack-based [5]. Dalvik had a Register-based architecture with custom Bytecode instructions [6]. Just because the language is expressed in a Java-like way (grammar) it does not imply that there has to be a JVM to execute the resulting program.

Further Mobile and Embedded Development topics are out of scope for the rest of this Wiki page.

If you are really interested, you can check out the development of Java technology specification (JSRs), where you will also find select security specifications like Bean Validation, JSR 303.
This is available in Spring (MVC, Boot), for example through Hibernate.


JVM, JEE, JSP, JCL, Java SE...

Here is the list of common abbreviations from the Java world. To make sure that references are understood in the same way.

Abbr. Name Short description
JVM Java Virtual Machine Software-machine that runs Java Bytecode
Java (Platform) SE Java Platform, Standard Edition Formerly known as J2SE Java SE defines a range of general-purpose APIs for the Java Class Library
JCL Java Class Library Java runtime libraries, builds interfaces and facades for Java SE
JEE Java Enterprise Edition Extensions for eCommerce, Accounting, Banking Information Systems, most notably Enterprise Java Beans, JavaServer Pages, and Java Persistence and Transaction APIs
JSR Java Specification Request RFCs within the Java Community Process
Servlet Java servlet Dynamic web content component, commonly for HTTP request handling
JSP JavaServer Pages Servlet based dynamic Web-page technology
JSF JavaServer Faces A standard component for Web UIs through JavaEE, uses JSP

Other terms

Hotspot: a Hotspot is a part of the program, that is executed many times. Therefore it’s critical for performance. Hotspots are not executed just-in-time (JIT), but are compiled ahead-of-time (AOT), and stored into code caches. Starting from Java 9 these code caches reside within a non-Heap memory region.

Java Bean: JavaBeans are essentially object-capsules, that follow a convention {7}. Their re-usability is supposed to speed up Java application development {8} in the sense “write once, run everywhere”.
Use cases for security include input validation via @SafeHtml annotations from the SafeHtmlValidator Bean in Hibernate. For details please jump to the Input Validation segment.

java-garbage-collector-types

G1: G1 often comes up during discussions. With Java 9 Oracle pushes G1 over Google’s ParallelGC.

name flag strengths weaknesses since
Serial Collector -XX:+UseSerialGC simple may freeze apps
CMS / concurrent-mark-sweep -XX:+USeParNewGC CMS - no pauses, higher CPU overhead
G1 -XX:+UseG1GC low CPU overhead, no stops uses more OS memory via Heap Java 9
ParallelGC -XX:+UseParallelGC control over pauses, throughput timing, uses OS memory via Heap Java 6
ShenandoahGC -XX:+UseShenandoahGC un-commits objects experimental Java 8

You can influence the JVMs memory-management:

Command-line part effect
java -XX:+Use[gc_name]GC see table above
-Xms32m steps in 32 MB
-Xmx2g Maximum scaling limit
-jar app.jar [sleep] sleep n seconds between load cycles
Command-line part effect
java -XX:+UseShenandoahGC see table above
-Xmx2g -Xms32m see table above
-XX:+UnlockExperimentalVMOptions enable uncommits
-XX:ShenandoahUncommitDelay=1000 garbage collector will start uncommitting memory that was not used for more than this time (in milliseconds)
-XX:ShenandoahGuaranteedGCInterval=10000 guarantees a GC cycle within the stated interval (in milliseconds)
-jar app.jar 10 see table above

Summary: if you create Micro-Services you may want to check Shenandoah[7] with its uncommit option. Maybe it’s stable enough for you?

References

{7} Stack Overflow: What is a JavaBean

{8} Java Wikibook, JavaBeans

Security by perspective

Rather than emphasizing on the bugs and vulnerability classes I structure this Wiki article to reflect the principles of Defensible Architecture (partly programming-language and language-ecosystem agnostic). This way you can not only create defensible applications, but you can also create applications where there is nothing left to defend.

If you have to defend, you have already lost

Still, I would like to use this section to review the basics and to collect appropriate references for the AppSec architecture and design-focused sections.
Concerning this, an AppSec program’s culmination is not the Static Application Security Testing (SAST) integration into DevOps Pipelines. On the contrary: SAST is just one basic component of the daily work within the Software Development Lifecycle to catch low-hanging fruits.


Today traditional Defensible Coding alone produces poor results. There is no logical reason to teach “Secure Coding” classes to developers (where we learn all about OWASP Top 10) if we don’t also learn a holistic approach to design solutions.


We do not want to write secure code. We want to develop features. Security is a feature.

(Source: reality)

Objectives:

  1. definition of the security feature and its story
  2. why and how to design a solution with the appropriate coverage
  3. what about Java?

Java is not secure by design, because you are the designer

Let us examine the following observations:

  • If you don’t evaluate user input in a Web App you will have to deal with Cross-Site Scripting (XSS) and SQL Injection (SQLi) bugs. Or even OS command-injections
  • If you pass unvalidated data to C / C++ based libraries (JNI) you may have to deal with common Buffer Overflows (Stack BOFs) or Null Character injections
  • JSON, XML injection, …, LDAP query-language injections… all kinds of injections may appear, regardless of the language or runtime environment
  • Directory traversal vulnerabilities may lead to arbitrary file disclosure, maybe via misconfigured (Java) web servers (like Tomcat). Now, this might not seem to be “a big deal”, but consider that de-compiling Java class files (Bytecode) back to Java code is possible. If we think about hard-coded passwords… I think we can see the problem. {2}

So that "Secure by design" is a misconception?

Let us examine the following observations:

  • The JRE has no understanding of confidentiality. Its sandbox has a long history of security bugs {3}
  • There can be Denial of Service (DoS) issues, which may disrupt the application availability.
  • Many Java apps load lots of JARs as dependencies from the Operating System’s Classpath, which can be backdoored (it’s an environment variable). That can be an integrity issue
  • Bad software architecture leads to security problems, e.g. by exposing or mishandling application-level secrets like (API) keys, certificates, etc…
  • Recent history shows, that Java’s security is bad at Object-level serialization, which is bad for distributed {4} systems or for high-performance systems which rely on Remote Method Invocation (RMI) like features
  • Type confusion vulnerabilities can be abused via Reflection to disable security features at runtime {5}

tl;dr: whoever told you that Java solves all security problems has been misinformed. Don’t spread fake news. Compared to other languages Java (and the framework of choice) reduces the time needed to implement features. Security is such a feature, together with many other business logic aspects that rely on it.

References

{1} IBM howto on JNI usage

{2} IntelliJ IDEA plugin for Java bytecode de-compiling

{3} Phrack article on Java Sandbox escapes, see 2.1 for a timeline

{4} Synopsis example of Java deserialization bugs and security impact

{5} ZDI blog and exploit - Java can throw lemons

Simplicity is key

We do not want methods that add new internal Entry Points with many parameters. Usually, many extra parameters introduce unnecessary branching. Instead, we want concise code and no code repetition.

Completeness - if needs else

Ensure that every if condition has got an else branch. switch gets a default to fallback into. If you find a lot of hanging conditionals, chances are that the Entry Point treatments haven’t been designed well.

Fail early

If you have to fail due to invalid data at any (internal or external) Entry Point, fail fast. This is good for performance and for security because you will have fewer race conditions / Denial of Service (DoS) problems. Depending on the failure mode of the program, you may want to fall back with a reasonable default and keep going.

Error handling

Errors happen, but Exceptions are not cheap. If you want to write secure and highly efficient code, think twice before you use exceptions.

Error handling can be simplified with pre-conditions, post-conditions, and invariants. Good developers will assert about Entry Points to generate the certainty for the execution-flow. This is usually simpler and faster than exception handling because you don’t have the Chain of Responsibility calling chain.

A global exception handler to keep the application (or service) running is a proper fallback in error handling design because assertions should be used with care.:slight_smile:

[… draft]

Process finished with exit code 0


  1. The JVM specification - too few people know what it is ↩︎

  2. A brief incomplete list of Java bytecode instructions on Wikipedia ↩︎

  3. Wikipedia list of JVMs ↩︎

  4. Example: Java to C# “converter” Java to C# Converter ↩︎

  5. Blog post, “JVM Memory Model” ↩︎

  6. Paper: “Virtual Machine Showdown: Stack Versus Registers” by Shi et al. (2005) ↩︎

  7. Main - Main - OpenJDK Wiki - OpenJDK 12+ incorporates it ↩︎