Letters to the Editor

Java Q&A

"Back to Your Class Roots"

Vladimir Roubtsov

Final declaration

Vladimir,

I have two questions for you:

  1. What does it mean when you write "[some comment]" in your Javadoc comments?
  2. In your method getClassLocation(), why is it necessary to declare cls as final Class and not simply Class?

Markus Neifer

Markus, I tend to detail simple pre- and post-conditions for method parameters (a simple form of Design-by-Contract, if you will) to make better use of my own Javadoc comments. For example, "[may not be null]" for a parameter usually indicates that it is illegal to pass a null object reference as the parameter value (the method will throw an IllegalArgumentException), and "[never null]" for the return value usually indicates that the method guarantees that it will never return null. Those are just elements of my personal coding style. Feel free to ignore them and change the code to suit your own conventions. In regards to your second question, declaring cls final is not necessary. Declaring method parameters (or local variables) final makes them constant in the sense that values of primitive types cannot be changed post initialization time (or after method entry), and values that are object references cannot be reassigned within the method. This const-ness is enforced by the compiler. getClassLocation() will function as before if you remove final from its parameter declarartion. Again, this is an element of my personal coding style. Since I have no need to change cls inside the method, why not make it final? I always start with declaring method parameters and local variables as final and undo that only if I truly need to reassign their values later on. This habit comes from the C++ language, which has a much more powerful and useful paradigm of const-correctness. This coding style has nothing to do with performance but rather helps me avoid copy-and-paste and other common types of mistakes. Vladimir Roubtsov Editor's note: See Vladimir's current Java Q&A for more on Class.

Java Q&A

"Cracking Java Byte-Code Encryption"

Vladimir Roubtsov

Changes for the JVM ahead?

Vladimir,

In the "Lessons Learned" section, you mentioned:

"Until JVM architecture changes to, say, support class decoding inside native code, you will be better off with traditional obfuscators that perform byte-code transformations."

Can you tell me about any anticipated changes in the JVM? Has this problem created a new clever form of protection?

Rafael Paiva

Rafael, I am unaware of any Java Specification Requests (JSRs) or other plans to enhance the JVM architecture to support secure encrypted class deployment. For now, if protecting your intellectual property is paramount to your work, I think using a well-tested commercial obfuscator is your best option. As far as I know, other managed runtime/byte code-based architectures (like .Net) suffer from the same problem. Vladimir Roubtsov

Cracked method?

Vladimir,

I have discovered your method for cracking encrypted byte code does not always work. If you implement your own findClass() method, it will not call the defineClass() method. I have encountered a program that has its own ClassLoader and generates the class file instance in native code.

How do you crack such an encryption? Can I turn a class instance back into a .class file as byte code?

Konig Muller

Konig, I can assure you that you are mistaken: overriding findClass() does not eliminate the eventual call to defineClass() (this method's native version, at least). At that point, the class definition can be easily intercepted via, say, a JVMPI (JVM Profiler Interface) agent (see a short comment about this toward the end of my article). The simple trick of manipulating java.lang.ClassLoader was merely the easiest way I could raise the issue. The article was already on the long side, and it would have taken even more space to explain how to do the same trick via JVMPI. I have encountered a program that has its own ClassLoader and generates the class file instance in native code. Other readers have pointed out the same possibility. However, class definitions done in native (Java Native Interface (JNI)) code via JNI's defineClass() still generate JVMPI events. I have a simple JVMPI agent that dumps class bytes to disk in response to JVMPI_EVENT_CLASS_LOAD_HOOK events, and I can assure it breaks products that generate class definition natively quite easily. However, the particular exploit one uses does not really matter: the fundamental point here is that no matter how you encrypt, you must eventually undo your own encryption and deliver the unencrypted class bytes to the JVM. At that point, it is easy to grab this unencrypted class definition and decompile it. The JVM sees it—and so can I sooner or later. For more comments along these lines see http://www.javaworld.com/javaworld/jw-05-2003/jw-0530-letters.html. Vladimir Roubtsov

More protection

Vladimir,

How does one reasonably protect IP with Java that gets deployed in the field?

Joe Higgins

Joe, The IP protection situation in the field falls into two general cases:

  1. It is a common case with enterprise software companies that their clients pay a lot of money for the software solutions, and so every software deal is accompanied by a great deal of contractual paperwork. The legal terms therein severely penalize any kind of attempts to use the provided solution in license-noncompliant ways. Think of it as "code protection through legalese." Coupled with normally good physical security of the machines running the eventual Java code, it makes the issue of someone stealing byte code a mostly nonexistant one in this domain.
  2. Another common situation is to write a Java app for mass market and make its demo versions available for public downloading. No tight control over who downloads the binaries (and perhaps attempts to crack them) is generally possible in this case. If IP protection is paramount, the only practical solution here is to use a byte-code obfuscator. A few of them have been in existence for a few years and are therefore presumably robust. Of course, using an obfuscator is like using a second-level compiler and leaves one wondering about possible new bugs introduced by it. Even if an obfuscator can be trusted to be bug-free, there is no guarantee that changing normal byte-code flow expected by, say, HotSpot will not render some of HotSpot's byte-code runtime optimizations less efficient.

Vladimir Roubtsov

Java Q&A

"Into the Mist of Serialization Myths"

Vladimir Roubtsov

Unrealistic expectations

Vladimir,

It is somewhat concerning that:

  1. Achieving timings in a loop are not necessarily a reflection of real-world iterations, particularly in discarding the startup case.
  2. The size and complexity of the test message object is also not reflective of a real-world range.
  3. The serialVersionUID is just the tip of the iceberg in concerns about Java "native" serialization. For a good discussion on this topic, I direct interested readers to Chapter 6 of O'Reilly's Java Enterprise Best Practices.

G. Boettcher

G, Let me address the objections you raise in your message: Achieving timings in a loop are not necessarily a reflection of real-world iterations, particularly in discarding the startup case. The article was clear about concerning itself with an application's steady state. I happen to think that the majority of nontrivial Java applications are like that (e.g., application servers). I have been programming in Java for several years, and this kind of application seems real world to me by now. The size and complexity of the test message object is also not reflective of a real-world range. Perhaps you can substantiate this claim? While it is obvious that no test object will ever be exactly like someone's real-world object (it is a test, after all), the classes you refer to you were borrowed largely from my "Attack of the Clones" article, and that in turn was inspired by my enterprise software work for a Fortune 100 client. Again, that's pretty real world to me. The serialVersionUID is just the tip of the iceberg in concerns about Java "native" serialization. Yes, my article was a very short Q&A written with a specific purpose to debunk a common performance myth. This myth keeps reoccurring in many forums and has even found its way into some books (e.g., Java RMI's "Versioning Classes" section). My message is simple: if performance is your only reason for setting serialVersionUID, you should reconsider. The article also shows how to do a microbenchmark properly (use a high-resolution timer, warm up HotSpot, etc.). At no point did I attempt to cover the entire topic of Java performance profiling and optimization, on which large books could be (and have been) written. Besides the book you refer to, I also recommend books by Jack Shirazi and Jeffrey Kesselman. Vladimir Roubtsov

"Power Java Programming—Free!"

Robert Swarr

jEdit versus Eclipse

Please convince me to use jEdit and not Eclipse.

Saurabh Gupta

Saurabh, I'm not going to try and convince you to use jEdit rather than Eclipse because I don't believe that any one editor or IDE is best for all developers. Each of us has to pick the software that's right for our particular needs. I've used a number of IDEs and liked many of their features. But, I still prefer jEdit because I place more importance on a powerful editor than a seamless IDE. You might make a different choice. The beauty of open standards and open source is that it frees us to make these choices. However, I will argue is that jEdit is a viable option to Eclipse for developers who value a lightweight editor that loads quickly and supports advanced features. Some highlights of its features are:

  • Syntax highlighting for a number of languages (I use Java, JavaServer Pages, PHP (Hypertext Preprocessor), XML, and HTML)
  • Folding (hiding sections of code to get a big picture view of the source file)
  • Unlimited undo/redo
  • Powerful file and directory searches
  • Extensive customization
  • Extensibility: plug-ins can turn jEdit into a full-fledged IDE

I suggest that you spend a few minutes reviewing jEdit features on its Website (

http://www.jedit.org/index.php?page=features

). If you like what you see, download it and try it. Robert Swarr

Tips 'N Tricks

"Java Tip 136: Protect Web Application Control Flow"

Romain Guay

Synchronicity

Romain,

Your article provides an excellent solution to the refresh or repeated request problem. I have one question: In the article, your perform method is not synchronized, while in your source code, the execute method is synchronized. Is it really necessary to synchronize the execute method? This will put concurrent requests from other users on hold (if the action takes a long time like database activity). If I remove synchronization from the execute method, I don't see any downside since everything is based on individual sessions.

Harish K.

Harish, The reason for synchronization is to protect multiple submits from the same session; that is, to ensure the first submit is complete before subsequent ones are processed. Try to remove the synchronized keyword and click multiple times on the submit button. The result is not guaranteed to be successful since the sequence in which the submits are treated is not dictated by any means. A look in the log will confirm this. However, I was also concerned about the downside of synchronizing as you mention. The solution is to synchronize on the session, but the session object provided by the Web container is a façade that is not guaranteed to be the same object. The solution I found was to synchronize on the session ID, which is the same String instance on every call. This gives:

public final ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
    HttpSession session = request.getSession();
    synchronized(session.getId()) {
        // Get the request token
        String requestToken = request.getParameter(REQUEST_TOKEN_KEY);
        ...

By the way, in regards to optimizing the code, the

cloneBean

on line 168 is not necessary; the action can be performed on the bean itself.

cloneBean

is necessary on recover only. I also wanted to avoid this, but I found no other means of preventing repopulation of the bean by upcoming requests. Let me know if you have any ideas. Another area of interest: I also did an implementation where the synchronized behavior is triggered by a flag provided by an abstract method (

isSynchronized (HttpServletRequest)

) that subclasses implement. This way, I can implement the synchronized action in a common superclass for all actions, and this flag dictates the behavior. Romain Guay