HTML5 and Java Application Security - Java EE and HTML5 Enterprise Application Developmentb (2014)

Java EE and HTML5 Enterprise Application Developmentb (2014)

CHAPTER

6

HTML5 and Java Application Security

As an application developer, you may get the sense that every time you obtain a good understanding of the latest security issue, a new one crops up. Staying ahead of the security curve may seem practically impossible, but there are basic development practices that you can follow that will help you to at least keep up with the security curve. Application security can take many forms. In the case of HTML5 and Java web applications, the two major forms of security are client-side security and server-side security. The top issues and common best practices that apply to client-side security and server-side security differ, so this chapter discusses each separately, starting with securing the client side.

Client-Side Security

When working with HTML5 applications, always keep in mind this important fact: different HTTP traffic analyzers can read just about anything that you send or receive.

image

TIP

You should treat all data entering and exiting your HTML5 application as potentially malicious.

While almost all security measures need to be implemented on the server side for HTML5 applications, there are still a few types of client-side attacks that you need to be aware of, and properly code against, to avoid having your application exploited by hackers. These attack types include cross-site scripting, cross-site request forgery, and clickjacking. You will also want to have a basic understanding of authentication and authorization practices for your application and finally, some commonsense practices that should always be used when doing client-side security coding.

Cross-Site Scripting

Cross-site scripting (XSS) is one of the most common security vulnerabilities in web applications. There are actually three different kinds of XSS attacks: reflected, stored, and DOM-based. Reflected and stored XSS attacks are server-side attacks that must be handled at the application server or web server, whereas DOM-based XSS attacks are client-side attacks that must be addressed by client-side developers.

XSS occurs when a web application incorporates user input into the output that it generates without first properly validating or encoding the input. Data coming from the end user (for example, form input) or from a data connection (for example, a REST service) is considered untrusted data. You didn’t create the data as part of your application, so you can’t verify that it came from a trusted source. It’s this untrusted data that you have to guard against.

The best way to understand XSS is to look at some examples. Although the focus of this section is client-side security, server-side XSS attacks are the easiest to understand, so a couple of examples of server-side XSS attacks are provided next, followed by a client-side example.

For the first example, assume that you’ve decided to create a custom error page for a 404 (file not found) error. When someone types in a URL similar to

image

image

the error page returns a message stating that the file not-here could not be found on the server. The XSS vulnerability occurs if the data displayed in the error message is not escaped properly before it’s read by the browser, in which case an attacker could do something like this:

image

image

The browser would execute the <script> when it parsed the data to display it as part of the error message.

For the second example, assume that your web application has a search box. When a user conducts a search, the results of the search are displayed on a separate results page. The XSS vulnerability occurs if the results page uses the very common pattern of displaying “x number of results found for: <display what was searched for>” and does not perform proper encoding of the search string. If a malicious user enters a search string similar to the <script> block in the previous example, the JavaScript will be executed when the search results page is loaded in the browser.

Both of the preceding examples would normally be managed on the server side, because the error page and the search results page would normally be generated on the server. As previously mentioned, the third kind of XSS attack is purely client side and deals with how JavaScript handles the execution of DOM elements.

To demonstrate how a DOM-based XSS attack works, we’ll use a similar example to the previous search field example. Suppose your HTML5 web application has a form that includes an input field requesting the user’s username. The form also includes a <div> element that will be updated to show the content of whatever the user typed into the input field when the user presses the ENTER key. Listing 6-1 shows the code for this example.

image

Listing 6-1 Form Example

image

image

You want to set the contents of this <div> element to the value of the string entered into the userName input field. Doing this with plain JavaScript may look something like Listing 6-2.

image

Listing 6-2 innerHTML Example

image

image

The code shown in Listing 6-2 will work just fine. However, by using the .innerHTML attribute of the <div> element, you have opened yourself up to a DOM-based XSS attack. If a malicious user were to enter a string that looked something like

image

image

the HTML would be added to the DOM as written, and the next time someone moves their mouse over the new <div> element, the JavaScript would be executed.

There are certain DOM attributes and methods that you should avoid when working with untrusted data. A partial list includes

image element.innerHTML

image document.write()

image document.writeln()

image javascript.eval()

image element eventHandlers

image .setTimeout

image .setInterval

image new function()

In general, if you are working with untrusted data, set up your HTML so you can use the element’s .textContext method, as shown in Listing 6-3, instead of trying to add HTML directly.

image

Listing 6-3 textContext Example

image

image

If you absolutely have to allow untrusted data into a context that can be executed by either JavaScript or the HTML parser, then you should learn how to use one of the many HTML and JavaScript encoders that are available. You could try to write an encoder yourself, but doing so can be tricky because each browser’s JavaScript engine can handle things a little bit differently. You are better off using an encoder that has been developed by a trusted security team, such as the Enterprise Security API (ESAPI) that is available from the Open Web Application Security Project (OWASP) team.

You should also be aware that using a JavaScript framework like jQuery poses the same issue. Using code such as

image

image

will open the same XSS attack vector as using .innerHTML. If you are using jQuery, make sure you use .text instead of .html:

image

image

image

NOTE

Modern versions of both Firefox and Chrome web browsers come equipped with a basic XSS auditor that will help prevent some kinds of XSS attacks. However, you should not rely on this functionality in any way as the sole method of protection. Using proper coding practices is the only way to truly protect against XSS attacks.

Cross-Site Request Forgery

Attacks that exploit the cross-site request forgery (CSRF) security vulnerability are uncommon because they are successful only under a very limited set of conditions. However, if you don’t take some measures to guard against CSRF attacks, you are exposing your website visitors to a potentially very nasty result.

A good way to explain the CSRF attack is to use an example of a banking website. Let’s call the website megabank.com. When you log into your account on this bank’s website, the login stores a session cookie in your browser. This is a perfectly normal and acceptable practice for a banking website. The CSRF vulnerability exists if you leave the website without first logging out manually by clicking the Logout button. Your browser still has that session cookie in its cache up until the cookie expires. The expiration of the session cookie is set by the megabank.com website and in most cases will expire approximately 15 minutes after the last activity on the website. This expiration time can vary though. Suppose you next navigate to some other website that happens to have been hacked to include malicious code that, when activated (via a button click, for example), instructs your browser to send a request to megabank.com to transfer funds from “your” account to the hacker’s account listed in the malicious code. When the megabank.com website receives the request, it will look for a session cookie to identify the user, which it will find in your browser because you just visited the website and didn’t log out. The transfer will go through as if you performed the request yourself.

Although the chances are low that all the variables required for a successful CSRF attack will be present, it would take only one successful attack to ruin the reputation of the megabank.com website. If you’ve encountered spam emails or spam forum comment posts that just have links in them to some seemingly random websites, they could very well be attempts to lure you into a CSRF attack. The worst part of the CSRF vulnerability is that the end user doesn’t even have to click anything on the website that is hacked. The entire attack can be handled via JavaScript when the page is loaded.

So, what can you do to help make sure your HTML5 application doesn’t allow this kind of CSRF attack? First, be aware that your application has to be maintaining a session cookie in order for this type of attack to happen. If your application doesn’t maintain session cookies (a stateless application), then it isn’t vulnerable to this type of attack and you do not need to do anything. If your application does maintain session cookies, then your first priority is to make sure your website isn’t susceptible to the XSS types of attack described in the previous section. If it is susceptible to XSS attacks, then anything you do to try and prevent CSRF attacks is meaningless.

To implement any kind of CSRF prevention in an HTML5 client-side application, you need to work in conjunction with what is being done on the server side of your application. The technique that you use to prevent CSRF is called double-sending cookies. This technique involves reading the session ID from the cookie that was sent from the server when the web page was first requested. Using JavaScript, you place that same session ID into a hidden field in all of the forms in your application, and attach it to any AJAX calls that your application makes back to the server. When sending the session ID value back to the server, it’s often referred to as a CSRF token.

image

NOTE

Never set a CSRF token on an AJAX call that uses the method type of GET. Doing so will potentially expose the CSRF token in many different places (server logs, browser logs, network monitors, and so forth).

Using code similar to that shown in Listing 6-4 will allow you to echo the current session ID back to the server, which will then check to make sure that it matches the session ID in the cookie. Using this technique makes it extremely unlikely that the server will receive from another website a request that has both the proper session cookie and the same session ID in a hidden form element.

image

Listing 6-4 CSRF Hidden Form Token

image

image

As you can see, the real solution to prevent CSRF attacks has to start at the server, but as a client-side developer, you can also do your part to protect against such attacks.

Clickjacking

Clickjacking is another type of attack against which you must protect your HTML5 web application. For a clickjacking attack to succeed, the attacker first must manage to wrap a web page from your application inside of a frame, or <iframe>, of some kind on a website that the hacker has created. The hacker creates a series of stacked transparent layers over the top of the website that the hacker created, which appears to be a normal website. When a website visitor thinks they are clicking buttons or links on this website, they are really interacting with your website and clicking a button or link that is not visible. Back in 2009, Chris Shiflett described an attack of this kind (http://shiflett.org/blog/2009/feb/twitter-dont-click-exploit) that used a Twitter page as the transparent overlay. When an end user clicked the visible “Don’t Click” button, they were actually clicking the Post button of the hidden Twitter page and sending out a tweet devised by the attacker.

As with most of these kinds of attacks, the best way to defend against clickjacking is to do so from the server side. In the case of clickjacking, the service-side defense is to set the X-Frame-Options response header to either deny all types of frames or to allow only frames from the same domain. However, there is one coding practice that you can use on the client side to protect your application from clickjacking.

If you cannot modify the response headers from the server side, or you need to support older browser versions that don’t understand the X-Frame-Options header, you can add the piece of code shown in Listing 6-5 to the <head> element of your pages to help protect against clickjacking attacks. This concept comes from Jason Li at Aspect Security and is discussed here: https://www.codemagi.com/blog/post/194.

image

Listing 6-5 Anti-clickjacking Example

image

image

Adding a <style> element to the top of your page enables the script that immediately follows it to know that it’s referencing your page. If you were to use only the else part of the code by itself, the expression could be defeated through multiple kinds of workarounds. With the code inListing 6-5, the script looks for the antiClickjack <style> element, and if it’s not already the top layer, it moves it to the top. This is the OWASP-recommended method for preventing clickjacking attacks from the client side.

Authentication and Authorization

Probably the most obvious security issue when developing an HTML5 web application is how to handle your application login. None of the coding examples presented thus far in this book have included a login process, but if your application is going to store information that is specific to a user and/or information that will help to make the user’s current visit to your application more enjoyable, then you will want to build some form of authentication into your application.

The most common method of authentication used for JavaScript applications is the OAuth standard. OAuth is an open standard for authentication. In 2006, a few developers from Twitter and Magnolia put together the concept for OAuth. Through the work of a small group of developers over the next year, a draft proposal for the OAuth standard was developed, resulting in a final draft that was released in October of 2007. In 2008, the OAuth specification was brought in front of a group of developers at the Internet Engineering Task Force (IETF) annual meeting for work on further standardization.

The OAuth 1.0 protocol was released in April 2010 as IETF RFC 5849 (http://tools.ietf.org/html/rfc5849). The OAuth standard is now the required authentication protocol for many leading web service APIs, such as Twitter, Flickr, Netflix, and others. The OAuth 2.0 specification was released as RFC 6749 (http://tools.ietf.org/html/rfc6749) in 2012. Although it is slowly gaining popularity across the Internet, many controversies arose throughout its development. Some of the original developers of the OAuth 1.0 protocol have resigned from the project because of disagreements over its direction and policies. To decide which of the two protocols to use in your specific situation, you will need to conduct further research on your own. It’s safe to say that if your application needs to support direct authentication, you should start with the OAuth protocol.

Without getting into the technical details of the protocol, OAuth enables a client application, often a web application, to act on behalf of a user, with the user’s permission. The main components of OAuth 2.0 are

image Client

image Authorization server

image Resource server

image Resource owner

The resource owner is an entity that can grant access to a protected resource. The client is the application that makes the access request on behalf of the resource owner. A client performs actions on a resource server based on authorization provided by the user at the authorization server. For example, a user can access images on www.flickr.com (resource server) via a web browser (client) by signing in to Flickr using their Google Account (where www.google.com is the authorization server). The advantage of this approach, as opposed to creating a separate login on www.flickr.com, is that the user does not have to create and remember multiple logins and passwords. Instead, the client obtains a bearer token from the authorization server, with the user’s approval, and stores it. Then, when the resource needs to be accessed at the resource server, the client sends a special HTTP header in the following form:

image

image

The token value is opaque to the client but can be decoded by a resource server so that the server can check that the client, on the user’s behalf, has permission to access the resource.

If your application is going to be used as part of a larger enterprise environment that requires user authentication, then your application probably does not need to provide separate authentication. If you do need to include some form of authentication in your application, there are plenty of libraries in different languages by different authorization servers and resource providers that provide OAuth support. It’s worth looking at them before deciding on your security infrastructure.

In a typical enterprise environment, your application will be part of a larger application server installation. This application server will do the authentication for your application, and the user will not get to your application’s pages until they have already been authenticated by the application server’s methods. This is also where the concept of authorization comes into play. Once the application server, or the identity management system that the application server is using, authenticates the end user, it can then be used to determine if the end user even has the rights, or isauthorized, to access your application. In such an environment, you will need to get information from your security team about what kinds of checks your application will need to implement to make sure it behaves properly within your specific environment.

Client-Side Security Common Sense

A commonsense approach to client-side security will help you to avoid many pitfalls. With that in mind, here are some commonsense practices that you should consider following:

image Try to always run your application using the HTTPS protocol.

image If your application is running in a secure domain (HTTPS), don’t connect your application to unsecured services. Make sure that your REST calls are also going to HTTPS domains and that your WebSocket calls are using wss instead of ws (see “WebSocket Security” later in the chapter).

image If at all possible, don’t allow <script> elements in your HTML files. Place your JavaScript in external files and reference them.

image If you are using a JavaScript framework, check to see what kind of help it provides with common security issues, and use those features.

image Finally, take the time to research which security measures your specific application requires. You’ll find that there is a lot of application security information available, and it’s growing rapidly.

Server-Side Security

This section explains the key concepts of server-side security: authentication, authorization, confidentiality, and data integrity.

image Authentication validates the identity of a client. It determines whether the client is, in fact, really what it is claiming to be. It usually involves receiving a request from a client that includes a user ID and credentials. The servlet container in a Java EE application server provides mechanisms to leverage standard web protocols and validate the credentials.

image Authorization ensures that the authenticated client has appropriate rights to access the requested resource. This allows the server to check if the user can invoke certain operations on your service. The servlet container typically defines the operations that can be performed.

image Confidentiality ensures that only the authorized recipients can access the information. This concept is similar to authorization, the key difference being that while authorization prevents the information from reaching unintended parties, confidentiality ensures that even if the information does reach unintended parties, it cannot be viewed or used.

image Data integrity ensures that the information has not changed while in transit between the client and server. A hashcode, or signature of the data, is sent along with the data and confirmed on the receiving side.

Let’s take a look at how these concepts can be realized in a Java EE container. After that, we’ll turn our attention to REST resource security and WebSocket security.

Authentication

There are different ways to achieve authentication; the first two types listed next are from the RFC 2617 draft standard:

image Basic Authentication This is the simplest method of authentication over HTTP. The client, most often a web browser, opens a login box prompting the user to enter a username and password. The client then sends a base64-encoded username and password to the service. The server then checks if the user account exists and verifies the sent password. If the username and password match those of the account, then the resource is made available; otherwise, an HTTP 401 response code is returned to the client, informing the client that it is not authorized to access the resource.

Under the covers, the client generates an HTTP Authorization header set to a base64-encoded string of the username, a colon character, and the password. The authorization method and a space (that is, “Basic ”) is added before this encoded string. If your username is “u1” and your password is “p1,” then the header will look like this:

image

Using Basic Authentication with HTTPS is highly recommended because otherwise the username and password can be easily decoded.

image Digest Authentication One of the limitations of Basic Authentication is that the password is sent in clear text and is susceptible to man-in-the-middle attacks. Digest Authentication, which is Basic Authentication over an encrypted HTTP connection, solves this problem.

Digest Authentication communicates credentials in an encrypted form by applying a hash function to the username, the password, a server-supplied nonce value, the HTTP method, and the requested URI.

For your username and password, the Authorization header looks like this:

image

Many of the security options in Digest Authentication are optional so the server may operate in a security-reduced mode. Even though it is slightly better than Basic Authentication, it is still not intended to replace stronger authentication protocols, like client-cert. Like Basic Authentication, Digest Authentication is also susceptible to man-in-the-middle attacks. These types of attacks can be avoided by using HTTPS instead of HTTP.

image Form-based Authentication Form-based authentication allows customization of the login screen and error pages that are presented to the client. The contents of an HTML page for a login page should be coded as follows:

image

The login form must contain fields for entering a username and a password. These fields must be named j_username and j_password, respectively. The action of the login form must be j_security_check.

The client is asked to enter the username and password and then click the Submit button, which submits the form to the server. If the authentication succeeds, the client is redirected to the requested resource. If the authentication fails, the error page is returned, which typically contains information about the failure.

image Client-Cert Authentication HTTPS not only provides a secure connection to the server but also can be used for authentication. This mechanism requires the client to possess a public key certificate (PKC) issued by a trusted organization, called a certificate authority. The PKC provides identification for the bearer. The server authenticates the client using this PKC.

The only disadvantage of this approach is the managing of the certificates themselves on both the client and server. Otherwise, this method is more secure than both Basic Authentication and form-based authentication.

All of these authentication mechanisms can be configured using the deployment descriptor (web.xml) of your application, as shown in Listing 6-6.

image

Listing 6-6 Deployment Descriptor Example

image

image

As you can see in Listing 6-6, the deployment descriptor has three main elements:

image The <security-constraint> element is used to associate security constraints with one or more web resource collections. It has the following subelements:

image <web-resource-collection> Identifies a subset of the resources and HTTP methods on those resources within a web application to which a security constraint applies. For example, in Listing 6-6, the security constraints are defined for the HTTP GET method on the resource accessible at /webresources/authors. Wildcards can be used to specify URL patterns, such as:
image

Once the user is authenticated, <web-resource-collection> defines which methods the user is authorized to access.

image <auth-constraint> Indicates the user roles that should be permitted access to this resource. The <role-name> used here must correspond to the <role-name> of one of the <security-role> elements defined for this web application. Alternatively, it can be the reserved role name, *, which indicates all roles in the web application. In other words, specifying the reserved role name * means that anybody who is able to log in can access the resource.

image <user-data-constraint> If specified, indicates that the resources are accessible over a secure transport. In Listing 6-6, the following element would need to be added:
image

If a client tries to access the resource using HTTP, it is redirected to an HTTPS URL instead. This ensures that the data transmitted cannot be observed by other entities and thus allows enforcing of the key concept of confidentiality.

The <transport-guarantee> subelement can also take the value of NONE or INTEGRAL. The later value ensures that the data cannot be changed in transit and thus allows enforcing the key concept of data integrity.

It is also important to note that if one <http-method> is listed in <security-constraint>, then that method is protected as defined by the constraints in the deployment descriptor. All other HTTP methods not explicitly listed are called as uncovered methods. Adding a top-level <deny-uncovered-http-methods/> element to the deployment descriptor can protect these methods.

image The <login-config> element is used to configure the authentication method and the realm name that should be used for this application. It has the following subelements:

image <auth-method> Configures the authentication mechanism for the web application. The element content must be BASIC, DIGEST, FORM, CLIENT-CERT, or a vendor-specific authentication scheme. The first four values correspond to the different authentication schemes explained earlier.

image <realm-name> Indicates the realm name to use for the authentication scheme chosen for the web application.

image The <security-role> element defines a security role. The subelement <role-name> designates the name of the security role. Note that these roles are created in an application server-specific way.

REST Resource Security

The following are some other guidelines to keep in mind when securing REST resources:

image Username and passwords, security tokens, or API keys should not appear in the URL, as these can be captured in web server logs and reused for malicious purposes.

image Every REST resource may not need to be read (GET), created (POST), updated (PUT), and deleted (DELETE). Make sure that only the required HTTP methods are exposed in the deployment descriptor and that other methods are explicitly protected using the mechanism defined earlier, such as <deny-uncovered-http-methods/>.

image Each user need not have access to all the REST resources. Use appropriate authorization by defining roles using <security-role> and giving access rights to resources accordingly using <auth-constraint>.

image For REST endpoints receiving multiple content types, always check the Content-Type header and use Bean Validation constraints, as discussed in Chapter 2, to restrict the types.

image Most third-party REST APIs allow authentication and authorization with popular OAuth providers like Google, Facebook, and Twitter. Consider integrating these providers instead of creating your own infrastructure from scratch.

WebSocket Security

WebSocket connections are upgraded from an existing HTTP connection. A plain WebSocket connection is established using the ws URI scheme, and a secure connection can be established using the wss URI scheme. This allows the WebSocket communication over standard ports 80 for plain text communication and 443 for secure communication, thus not requiring opening additional ports in firewalls. This also allows many existing HTTP security mechanisms to apply to a WebSocket connection.

WebSocket uses an origin-based security model policy commonly used by web browsers. RFC 6454 (www.ietf.org/rfc/rfc6454.txt) defines how user agents, such as browsers, isolate content retrieved from different origins (scheme, host, and port combination of the URL) to prevent malicious website operators from interfering with the operation of benign websites. Basically, content retrieved from one origin can interact freely with other content retrieved from that same origin, but it is restricted on how it can interact with content retrieved from a different origin. RFC 6454 defines an HTTP header field, named Origin, that indicates which origins are associated with an HTTP request. A WebSocket opening handshake from a browser is required to have this header so that subsequent requests can be serviced accordingly. However, this model does not work when a non-browser client initializes WebSocket connections.

In addition to the Origin field, the WebSocket opening handshake is required to have a Sec-WebSocket-Key field. This field is sent from the client as part of the opening handshake and is used by the server to prove that it received a valid WebSocket opening handshake. This helps to ensure that the server does not accept connections from non-WebSocket clients (for example, HTTP clients) that may be abused to send data to unsuspecting WebSocket servers.

As you can see, WebSocket already provides a decent level of protocol-level security. In addition, WebSocket endpoints within a Java EE application can be secured using the web container security model. A WebSocket mapped to a given ws:// URI is protected in the deployment descriptor with a listing to an http:// URI with the same hostname, port, and path since this is the URL of the opening handshake. A WebSocket application may use Basic Authentication or form-based authentication prior to the opening handshake. Similarly, WebSocket authorization may be set by adding a <security-constraint> element to the deployment descriptor. The <url-pattern> used in the security constraint is used to match the request URI of the opening handshake of WebSocket. Finally, a <transport-guarantee> of CONFIDENTIAL allows WebSocket communication over an encrypted wss:// connection. This allows WebSocket applications to assign an authentication scheme, user roles, and a transport guarantee using standard mechanisms.

Summary

The HTML5 specification provides many new features that also bring their own potential security issues. While this book is focused specifically on HTML5 interactions with web services of REST, WebSocket, and Server-Sent Events, there may be other areas that you will want to research, such as local-storage, geolocation, and more.

The Open Web Application Security Project (OWASP) is a worldwide, not-for-profit organization whose main focus is on improving security in software. This organization’s website (www.owasp.org) is a great resource for researching existing and potential security issues in all areas of HTML5 development.