Book Review: Iron-Clad Java: Building Secure Web Applications
MVB Adrian Citu reviews 'Iron-Clad Java: Building Secure Web Applications' chapter-by-chapter, and explains why it's a must-read.
Join the DZone community and get the full member experience.Join For Free
This a review of the Iron-Clad Java: Building Secure Web Applications book.
I will start with the conclusion because it’s maybe the most important part of this review.
For me this is a must read book if you want to write more robust (web and non-web) applications in Java. It covers a very large panel of topics from the basics of securing web applications using HTTP/S response headers to handling the encryption of sensitive information in the right way.
Chapter 1: Web Application Security Basics
This chapter is an introduction to the security of web applications, and it can be split in 2 different items.
The first type of item is what I would call “low-hanging fruit”, or how you could improve the security of your application with a very small effort:
- The use of HTTP/S POST request method is advised over the use of HTTP/S GET. In the case of POST, the parameters are embedded in the request body, so the parameters are not stored and visible in the browser history, and if used over HTTPS are opaque to a possible attacker.
- The use of the HTTP/S response headers:
- Cache-Control – Directive that instructs the browser how it should cache the data.
- Strict-Transport-Security – Response header that forces the browser to always use the HTTPS protocol. Thus, it can protect against protocol downgrade attacks and cookie hijacking.
- X-Frame-Options – Response header that can be used to indicate whether or not a browser should be allowed to render a page in a
<object>. Sites can use this to avoid clickjacking attacks by ensuring that their content is not embedded into other sites.
- X-XSS-Protection – Response header that can help stop some XSS atacks (this is implemented and recognized only by Microsoft IE products).
The second types of items are more complex topics like the input validation and security controls. For this items the authors just scratch the surface because all of this items will be treated in more details in the future chapters of the book.
Chapter 2: Authentication and Session Management
This chapter is about how a secure authentication feature should work; under the authentication topic is included the login process, session management, password storage, and the identity federation.
The first part presents the general workflow of login and session management (see next picture) and some dos and don’t are described for every step of the workflow.
Login and session management workflow
The second part of the chapter is about common attacks on authentication, and for each kind of attack, a solution to mitigate it is also presented. This part of the chapter is strongly inspired by the OWASP Session Management Cheat Sheet, which is rather normal because one of the authors (Jim Manico) is the project manager of the OWASP Cheat Sheet Series.
If you want to have a quick view of this chapter, you can take a look at the Authentication and Session Management presentation by Jim.
Even if you are not implementing an authentication framework for your application, you could still find good advice that can be applied to other web applications; like the use of secured and http-only attributes for cookies and the increase of the session ID length.
Chapter 3: Access Control
The chapter is about the advantages and pitfalls of implementing an authorization framework and can be split in three parts.
The first part describes the goal of an authorization framework and defines some core terms:
- Subject: The service making the request
- Subject attributes: The attributes that define the service making the request.
- Group: Basic organizational structure.
- Role: A functional abstraction that uniquely describes system collaborators with similar or unique duties.
- Object: Data being operating on.
- Object attributes: The attributes that define the type of object being operating on.
- Access control rules: Decisions that need to be made to determine if a subject is allowed to access an object.
- Policy enforcement point: The place in the code where the access control check is made.
- Policy decision point: The engine that takes the subject, subject attributes, object, and object attributes and evaluates them to make an access control decision.
- Policy administration point: Administrative entry in the access control system.
The second part of the chapter describes some access control (positive) patterns and anti-patterns.
Some of the (positive) access control patterns have a centralized policy enforcement point and policy decision point (not spread through the entire code), all the authorization decisions should be taken on server-side only (never trust the client), the changes in the access control rules should be done dynamically (should not be necessary to recompile or restart/redeploy the application).
For the anti-patterns, some of them are just the opposite of the (positive) patterns, like hard-coding policies (opposite of “changes in the access control rules should be done dynamically”) and adding the access control manually to every endpoint (opposite of have a centralized policy enforcement point and policy decision point).
Other anti-patterns are around the idea of never trusting the client: Do not use request data to make access control policy decisions and fail open (the control access framework should cope with wrong or missing parameters coming from the client).
The third part of the chapter is about different approaches (actually two) to implement an access control framework. The most used approach is RBAC (Role Based Access Control) and is implemented by some well-known Java access control frameworks like Apache Shiro and Spring Security. The most important limitation of RBAC is the difficulty of implementing data-specific/contextual access control. The use of ABAC (Attribute Based Access Control) paradigms can solve the data-specific/contextual access control but there are no mature frameworks on the market implementing this.
Chapter 4: Cross-Site Scripting Defense
This chapter is about the most common vulnerability found across the web and have two parts; the presentation of different types of cross-site scripting (XSS) and the ways to defend against it.
XSS is a type of attack that consists of including untrusted data into the victim's (web) browser. There are three types of XSS:
- Stored XSS (Persistent XSS) – The malicious script is stored on the server hosting the vulnerable web application (usually in the database), and it is served later to other users of the web application when the users are loading the vulnerable page. In this case the victim does not require to take any attacker-initiated action.
- DOM-based XSS – The attack payload is executed as a result of modifying the DOM “environment” in the victim’s browser.
For all defense techniques, the big picture is that the input validation and output encoding should fix (almost) all the problems but very often various factors needs to be considered when deciding the defense technique.
Chapter 5: Cross-Site Request Forgery Defense and Clickjacking
The chapter dedicated to the Cross-Site Request Forgery (CSRF) has the same structure as the previous chapter (dedicated to the XSS); the first part defines the CSRF and how it works and the second part defines mitigation strategies.
CSRF is an attack that can be used to force the victim to trigger unwanted actions on a web application in which they’re currently authenticated.
CSRF and XSS can be related in the sense that a XSS vulnerability could be used in order to embed a CSRF attack in the victim web site but most importantly a XSS vulnerability can be used to avoid CSRF defenses; XSS can be used to read any (CSRF) tokens from any page or a XSS vulneariblity can be used to access cookies not having the HTTPOnly flag.
The following mitigations techniques are presented:
- Synchronizer token pattern – An anti-CSRF token is created and stored in the user session and in a hidden field on subsequent form submits. At every submit the server checks the token from the session matches the one submitted from the form. Tomcat 6+ implements this pattern; for more infos please see CSRF Protection Filter.
- Double-cookie submit pattern – When a user authenticates to a site, the site should generate a (cryptographically strong) pseudo-random value and set it as a cookie on the user’s machine separate from the session id. The site does not have to save this value in any way, thus avoiding server side state. The site then requires that every transaction request include this random value as a hidden form value (or other request parameter). A cross origin attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy. The AngularJS framework implements this pattern out of the box; see Cross Site Request Forgery (XSRF) Protection
- Challenge/response pattern – The solution consists in forcing the user a value known only to him in order to complete the action.
Chapter 6: Protecting Sensitive Data
This chapter is articulated around three topics: how to protect (sensitive) data in transit, how to protect (sensitive) data at rest, and the generation of secure random numbers.
How to Protect the Data in Transit
The standard way to protect data in transit is by use of Transport Layer Security (TLS). In the case of web applications, all the low level details are handled by the web server/application server and by the client browser, but if you need a secure communications channel programmatically you can use the Java Secure Sockets Extension (JSSE). The author's recommendation for a cipher suite is to use the JSSE defaults.
Another topic covered by the authors is about certificate and key management in Java. The notions of trustore and keystore are very well explained, and examples of how to use the keytool tool are provided. Last but not least examples about how to manipulate the trustores and keystores programmatically are also provided.
How to Protect Data at Rest
The goal is how to securely store the data but in a reversible way, so the data must be wrapped in protection when stored, and the protection must be unwrapped later when it is used.
For this kind of scenario, the authors are focusing on Keyczar, which is a (open source) framework created by the Google Security Team with a goal to make it easier and safer to use cryptography for developers. The developers should not be able to inadvertently expose key material, use weak key lengths or deprecated algorithms, or improperly use cryptographic modes.
Examples are provided about how to use Keyczar for encryption (symmetric and asymmetric) and for signing purposes.
Generation of Secure Random Numbers
The last topic of the chapter is about Java support for the generation of secure random numbers, like the optimal way of using the java.security.SecureRandom (knowing that the implementation depends on the underlying platform) and the new cryptographic features of Java8 (enhance of the revocation certificate checking, TLS Server name indication extension).
Chapter 7: SQL Injection and Other Injection Attacks
This chapter is dedicated to the injections attacks; the sql injection being treated in more details that the other types of injection.
The sql injection mechanism and the usual defenses are very well explained. What is interesting is that the authors are proposing solutions to limit the impact of SQL injections when the “classical” solution of query parametrization cannot be applied (in the case of legacy applications for example): the use of input validation, the use of database permissions and the verification of the number of results.
Other Types of Injections
XML injection, JSON-Based injection, and command injection are very briefly presented and the main takeaways are the following:
- Use a safe parser (like JSON.parse) when parsing untrusted JSON
- When received untrusted XML, an XML schema should be applied to ensure proper XML structure.
- When XML query language (XPath) is intermixed with untrusted data, query parametrization or encoding is necessary.
Chapter 8: Safe File Upload and File I/O
The chapter speaks about how to safely treat files coming from external sources and to protect against attacks like file path injection, null byte injection, and quota overloaded Dos.
The main takeaways are the following: validate the filenames (reject filenames containing dangerous characters like “/” or “\”), set a per-user upload quota, save the file to a non-accessible directory, create a filename reference map to link the actual file name to a machine generated name, and use this generated file name.
Chapter 9: Logging, Error Handling, and Intrusion Detection
What should be be logged: what happened, who did it, when it happened, what data has been modified, and what should not be logged: sensitive information like session IDs and personal information.
With error handling, the main idea is to not leak stack traces that could give valuable information about your application/infrastructure to an attacker. It is possible to prevent this by registering to the application level static pages for each type of error code or by exception type.
The last part of the chapter is about techniques to help monitor, end, detect, and defend against different types of attacks. Besides the “build it yourself” solutions, the authors are also presenting the OWASP AppSensor application.
Chapter 10: Secure Software Development Lifecycle
The last chapter is about the SSDLC (Secure Software Development Life Cycle) and how security could be included in each step of the development cycle. For me, this chapter is not the best one but if you are interested in this topic I highly recommend the Software Security: Building Security In book (you can read my own review of the book here, here, and here).
Published at DZone with permission of Adrian CITU, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.