Handling Security in Ajax Applications


So how do you handle security in Ajax applications? The general answer is that, if security is important, you ask the user to log in, giving username and password, and record both. You’ll see a number of ways of doing that in Ajax applications in the following sections.

Easy password protection

The easiest way to implement password protection is to do it yourself, asking the user for a password and then checking it yourself on the server. Because the user can’t download server-side scripts, your password-checking code is safe.

Here’s an example, checker.html. This example displays a password field, asking the user for his or her password:

 <body>   <H1>Easy password protection</H1>   <form>     Enter your password:     <input type = "password" name="text">     <br>     <br>     <input type = "button" value = "Display Message"       onclick = "getData('checker.jsp', 'targetDiv')">   </form>   <div >     <p>The fetched data will go here.</p>   </div> </body>

This example also displays a button, and when the user clicks that button, the JavaScript passes the password to the server-side script, a JavaServer Page, checker.jsp. Everything starts as usual, by getting an XMLHttpRequest object:

 <html>   <head>     <title>Easy password protection</title>     <script language = "javascript">       var XMLHttpRequestObject = false;       if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new           ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)       {         if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);           .           .           .           }           XMLHttpRequestObject.send(null);         }       }     </script>   </head>

The password is added to the end of the URL sent to the server like this:

 <html>    <head>      <title>Easy password protection</title>      <script language = "javascript">       var XMLHttpRequestObject = false;        if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new            ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)        {          if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);            XMLHttpRequestObject.open("GET", dataSource              + "?password=" +              document.getElementById("text").value);            XMLHttpRequestObject.onreadystatechange = function()            {              if (XMLHttpRequestObject.readyState == 4 &&                XMLHttpRequestObject.status == 200) {                  obj.innerHTML =                    XMLHttpRequestObject.responseText;              }            }            XMLHttpRequestObject.send(null);          }       }     </script>   </head>      .     .     .  </html>

In the server-side script, checker.jsp, you need a way of recovering the password. You can recover the password, encoded under the parameter name password, using the expression request.getParameter("password") in JSP. And you can check whether that password equals the one you’re expecting-say, opensesame-this way:

 <%    if(request.getParameter("password").equals("opensesame")){          .          .          .    } %>

If the password matches, you can send back a confirming message using Ajax and the JSP out.println method, which sends text back to the browser:

 <%    if(request.getParameter("password").equals("opensesame")){      out.println("You're in.");    } %>

Otherwise, you can let the user know he or she has not been accepted:

 <%   if(request.getParameter("password").equals("opensesame")){     out.println("You're in.");   }   else {     out.println("Wrong password");   } %>

You can see checker.html at work in Figure 15.6, where the user has entered the password.

image from book
Figure 15.6: The checker.html page

When you click the Display Message button, Ajax fetches the data, as shown in Figure 15.7.

image from book
Figure 15.7: The checker.html application lets you in.

On the other hand, if you enter the incorrect password, you’re not admitted, as shown in Figure 15.8.

image from book
Figure 15.8: The checker.html application says no way.

That’s one way to support passwords in Ajax applications. But there are many other ways as well.

Server-side user authentication

Another way to support passwords in Ajax applications is by implementing server-side user authentication, so that users are asked for their names and passwords when they interact with your site. The normal way of doing this is to have the server ask the browser to display that familiar login dialog that asks the user for their username and password.

That login dialog normally appears when you first navigate to a page, but it turns out that accessing a site using an XMLHttpRequest object can also trigger the dialog. To see this in action, you must first create a login name and password for a fictitious user, and you do that in Tomcat by editing the file tomcat-users.xml, which is in the Tomcat conf directory.

Presently, this file looks like this:

 <!--   NOTE:  By default, no user is included in the "manager" role required   to operate the "/manager" web application.  If you wish to use this app,   you must define such a user - the username and password are arbitrary. --> <tomcat-users>   <user name="tomcat" password="tomcat" roles="tomcat" />   <user name="role1"  password="tomcat" roles="role1"  />   <user name="both"   password="tomcat" roles="tomcat,role1" /> </tomcat-users> 

Here, users have a name and a password, and a role. A role corresponds to a region on the server that users are admitted to when they log on, and you’ll see how to set a role in the next page or two. To create new users, you might give them the password tomcat and the role ajax:

 <!--   NOTE:  By default, no user is included in the "manager" role required   to operate the "/manager" web application.  If you wish to use this app,   you must define such a user - the username and password are arbitrary. --> <tomcat-users>   <user name="tomcat" password="tomcat" roles="tomcat" />   <user name="role1"  password="tomcat" roles="role1"  />   <user name="steve"  password="tomcat" roles="ajax"  />   <user name="both"   password="tomcat" roles="tomcat,role1" /> </tomcat-users>

Next, you have to restrict the data you want to download using Ajax to that new ajax role. You do that in a file called web.xml, which configures Java-enabled Web applications. You can divide up Web applications by folder, such as placing this chapter’s examples in a folder named chap15:

 tomcat   |   |__chap15

Inside the chap15 folder, you need a directory named WEB-INF, which contains configuration data, and which has two required subfolders named classes and lib (which must be present, even if they’re empty):

 tomcat   |   |__chap15        |        |__WEB-INF            |            |__classes            |            |__lib 

The web.xml file goes in the WEB-INF directory, and you can use this file to specify which parts of your Web application are parts of a particular role. For example, say that you have a file named data.txt that you want to restrict access to, in a folder named data:

 tomcat   |   |__chap15        |        |__data        |  |        |  |__data.txt        |        |__WEB-INF            |            |__classes            |            |__lib

How could you restrict access to that file to users logged in under the ajax role? You can do that in web.xml. Here’s how web.xml starts, with a <web-app> element that configures your Web application:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application       2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>         .         .         . </web-app> 

To specify that you want to configure the role for the data folder’s contents, you can use a <security-constraint> element, containing a <web-resource> element like this:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application        2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <security-constraint>     <web-resource-collection>       <web-resource-name>Secure Area</web-resource-name>         .         .         .     </web-resource-collection>         .         .         .   </security-constraint> </web-app>

and you can specify the data folder’s contents with a <url-pattern> element:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application       2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <security-constraint>     <web-resource-collection>       <web-resource-name>Secure Area</web-resource-name>       <url-pattern>/data/*</url-pattern>     </web-resource-collection>         .         .         .   </security-constraint>   <login-config>     <auth-method>BASIC</auth-method>     <realm-name>Ajax Area</realm-name>   </login-config> </web-app>

Finally, you can specify the role that the contents of the data folder are in, the ajax role, with an <auth-constraint> element:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application        2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <security-constraint>     <web-resource-collection>       <web-resource-name>Secure Area</web-resource-name>       <url-pattern>/data/*</url-pattern>     </web-resource-collection>     <auth-constraint>       <role-name>ajax</role-name>     </auth-constraint>   </security-constraint>           .           .           . </web-app>

Next, you indicate that you want the browser to ask for the username and password using a dialog box-a process known as “basic” authentication-with a <login-config> element:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application       2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <security-constraint>     <web-resource-collection>       <web-resource-name>Secure Area</web-resource-name>       <url-pattern>/data/*</url-pattern>     </web-resource-collection>     <auth-constraint>       <role-name>ajax</role-name>     </auth-constraint>   </security-constraint>   <login-config>         .         .         .   </login-config> </web-app>

Inside the <login-config> element, you specify that you want to use basic authentication thisway:

 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application        2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <security-constraint>     <web-resource-collection>       <web-resource-name>Secure Area</web-resource-name>       <url-pattern>/data/*</url-pattern>     </web-resource-collection>     <auth-constraint>       <role-name>ajax</role-name>     </auth-constraint>   </security-constraint>   <login-config>     <auth-method>BASIC</auth-method>     <realm-name>Ajax Area</realm-name>   </login-config> </web-app>

That sets up the login username and password. Now even if you use an XMLHttpRequest object to access data.txt in the data folder, you’ll still be asked for your username and password.

You can see this at work in a new example, password.html, which starts simply by displaying a button, letting the user fetch data using Ajax:

 <body>   <H1>Ajax security at work</H1>   <form>     <input type = "button" value = "Display Message"       onclick = "getData('data/data.txt', 'targetDiv')">   </form>   <div >     <p>The fetched data will go here.</p>   </div> </body>

When the user clicks the button, the getData function connects to the server and attempts to download data/data.txt:

 <html>    <head>      <title>Ajax security at work</title>      <script language = "javascript">       var XMLHttpRequestObject = false;        if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new            ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)        {          if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);            XMLHttpRequestObject.open("GET", dataSource);            XMLHttpRequestObject.onreadystatechange = function()            {              if (XMLHttpRequestObject.readyState == 4 &&                XMLHttpRequestObject.status == 200) {                  obj.innerHTML =                    XMLHttpRequestObject.responseText;              }            }            XMLHttpRequestObject.send(null);          }       }     </script>   </head>  </html>

However, as you know, this is not going to be successful until the user enters his or her username and password. You can see password.html in Figure 15.9.

image from book
Figure 15.9: The password.html page

When you click the Display Message button, the login dialog box appears, as shown in Figure 15.10.

image from book
Figure 15.10: The password.html application’s login dialog box

After entering the username and password into the login dialog box, you gain access to the Ajax data, which is downloaded as shown in Figure 15.11.

image from book
Figure 15.11: Downloading password protected Ajax data

As you can see, access can be password protected, even if you’re dealing with XMLHttpRequest objects.

You can do more with Java-enabled Web applications as well: you can track who is logging in, as shown in a new example, password2.html, which calls a JSP page, user.jsp, to report the current user’s username:

 <html>   <head>     <title>Ajax security at work</title>     <script language = "javascript">       var XMLHttpRequestObject = false;       if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new           ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)       {         if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);           XMLHttpRequestObject.open("GET", dataSource);           XMLHttpRequestObject.onreadystatechange = function()           {             if (XMLHttpRequestObject.readyState == 4 &&               XMLHttpRequestObject.status == 200) {                 obj.innerHTML =                   XMLHttpRequestObject.responseText;             }           }           XMLHttpRequestObject.send(null);         }       }     </script>   </head>   <body>     <H1>Ajax security at work</H1>     <form>       <input type = "button" value = "Display Message"         onclick = "getData('data/user.jsp', 'targetDiv')">     </form>     <div >       <p>The fetched data will go here.</p>     </div>   </body> </html>  

The user.jsp page starts by including the java.security package to give the code in the page access to the methods it will need to recover the user’s username:

 <%@ page import="java.security.*" %>         .         .         .

Then the code in user.jsp uses the request object’s getUserPrincipal method to get data about the user in a Principal object this way:

 <%@ page import="java.security.*" %> <%   Principal principal = request.getUserPrincipal();         .         .         . %>

Now the code can use the Principal object’s getName method to return the user’s username to the browser:

 <%@ page import="java.security.*" %> <%   Principal principal = request.getUserPrincipal();   out.println("Your username is: " + principal.getName()); %>

That’s all it takes. Now when a user logs in, you can echo his or her username back to the browser, as shown in Figure 15.12.

image from book
Figure 15.12: Echoing the user’s username

In fact, you can avoid the whole login dialog completely when using the XMLHttpRequest object. Here’s what that object’s open method looks like in general:

 open("method", "URL"[, asyncFlag[, "userName"[, "password"]]])

Here are what these various parameters mean-note in particular that you can specify the login username and password:

  • method: This is the HTTP method used to open the connection, such as GET, POST, PUT, HEAD, or PROPFIND.

  • URL: This is the requested URL.

  • asyncFlag: A Boolean value indicating whether the call is asynchronous. The default is true.

  • userName: The username.

  • password: The password.

Here’s an example, password3.html, which starts by asking the user for his or her username:

 <body>   <H1>Ajax security at work</H1>   <form>     Enter your username:     <input type = "text" name = "username">     <br>     <br>       .       .       .     <input type = "button" value = "Display Message"       onclick = "getData('data/user.jsp', 'targetDiv')">   </form>   <div >     <p>The fetched data will go here.</p>   </div> </body>

and then asks for the user’s password in a password control:

 <body>   <H1>Ajax security at work</H1>   <form>     Enter your username:     <input type = "text" name = "username">     <br>     <br>     Enter your password:     <input type = "password" name = "password">     <br>     <br>     <input type = "button" value = "Display Message"        onclick = "getData('data/user.   </form>   <div >     <p>The fetched data will go here.</p>    </div>  </body> 

Then the code creates an XMLHttpRequest object in the usual way:

 <html>   <head>     <title>Ajax security at work</title>     <script language = "javascript">       var XMLHttpRequestObject = false;       if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new           ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)       {         .         .         .         }       }     </script> </head>

In the getData function, you can configure the open method call by including the user’s username and password like this:

 <html>    <head>      <title>Ajax security at work</title>      <script language = "javascript">       var XMLHttpRequestObject = false;        if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new            ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)        {          if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);            XMLHttpRequestObject.open("GET", dataSource, true,            document.getElementById("username").value,             document.getElementById("password").value);            .           .           .         }       }     </script> </head> 

Having configured the XMLHttpRequest object to include the username and password, you can set up the Ajax callback and send a value of null to the server:

 <html>    <head>      <title>Ajax security at work</title>      <script language = "javascript">       var XMLHttpRequestObject = false;        if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new            ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)        {          if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);            XMLHttpRequestObject.open("GET", dataSource, true,            document.getElementById("username").value,             document.getElementById("password").value);          XMLHttpRequestObject.onreadystatechange = function()          {            if (XMLHttpRequestObject.readyState == 4 &&              XMLHttpRequestObject.status == 200) {                obj.innerHTML =                  XMLHttpRequestObject.responseText;            }          }          XMLHttpRequestObject.send(null);        }     }   </script> </head> 

On the server side, you can use the same password-protected JSP as before, user.jsp:

 <%@ page import="java.security.*" %> <%   Principal principal = request.getUserPrincipal();   out.println("Your username is: " + principal.getName()); %>

Now users can enter their username and password in your application, as shown in Figure 15.13.

image from book
Figure 15.13: Entering the user’s username and password

And this login process works, as you see in Figure 15.14, where the user’s username is echoed to the browser.

image from book
Figure 15.14: Echoing the user’s username

Using usernames and passwords is one of the strongest techniques you have of ensuring security in Ajax applications, especially if you record who’s logging in when. But who’s going to protect the password? When your users log in over the Internet, their usernames and passwords are freely accessible, and so security could be a serious concern.

To protect username and password, you can use a secure protocol, such as HTTPS. HTTPS involves some extra setup, however, and is not available on all Web servers. An easily implemented alternative is to use public and private keys, which are discussed in the next section.



Ajax Bible
Ajax Bible
ISBN: 0470102632
EAN: 2147483647
Year: 2004
Pages: 169

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net