VECR IO Authentication


For interactive IO, the VECR environment uses an applet which connects back through the web server as a proxy to talk to a Java-based server. The focus of this document is on the security, or possible insecurity, of the method used for authentication.

Background

The applet starts by requesting a proxy connection through the web server to localhost port 7 where a Java server is listening.


Initial Applet Connection

The applet diagnostic window displays the web server response:

* Connecting to ftp.ece.villanova.edu:80
* Sending proxy request: CONNECT localhost:7
HTTP/1.0 200 Connection Established
Proxy-agent: Apache

* Sending authentication data for frodo
Note that no authentication is provided to the web server, anyone can connect through the server to localhost:7, for example, from fog.misty.com:
fog% telnet ftp.ece.villanova.edu 80
Trying 153.104.63.227...
Connected to ftp.ece.villanova.edu.
Escape character is '^]'.
CONNECT localhost:7
HTTP/1.0 200 Connection Established
Proxy-agent: Apache

abc
123

^]
telnet> quit
Connection closed.
fog%
Once the proxy connection is established, the web server is transparent and simply forwards data, including authentication data, back and forth between the remote user and the server on localhost port 7.

When it receives a connection, the Java server creates a client thread to communicate with the applet.


Applet, Client, and User Process

In the figure above, the transparent web server proxy between the Applet and Copy/Client threads is not shown. After creating the client thread, the Java server is no longer involved in the communications but is shown to complete the diagram of parent/child process relationships drawn with dashed lines. That is, the Server, running as root, creates the Client thread, also running as root. After verifying authentication data from the applet, the Client thread creates a Copy thread, running as root, to handle copying program output back to the applet. The Client thread also creates a Run process, running as the user, which runs and monitors the user program. When needed for the Save option, the Client thread creates a temporary Save process which is not shown in the figure.

Authentication

The first question regarding authentication is: where should it occur? One answer is to have the web server perform authentication. But this would require the applet to send the UserID and Password, and an applet does not have access to that data even if cached by the web browser. So the applet would have to prompt the user to enter their UserID and Password, and that would happen over and over again, any time the IO option is selected or the applet restarted. That would be an excessive annoying burden for the user, considering that they have already authenticated in order to get the applet web page in the first place.

Furthermore, if the web server performs authentication, it would not pass the authentication data through to the localhost:7 connection, so the Java server would have no way of securely knowing the UserID. The UserID could be a parameter passed by the applet to the server, but that could easily be faked and allow one user to access another users files through the server.

So it seems that authentication must be performed by the Java server, not the web proxy, and it must be done without have the user reenter their UserID and Password. This is implemented in VECR/IO using a secure authenticated ticket as follows.

When the IO option is selected, the user has already been authenticated to the web server, and the following shell code is run:

IO)
    #
    # generate IO applet HTML
    #
    case "$file" in # add debug here to run gdb ZZ
      *.c) prog=./`basename "$file" .c`;;
      *.java) prog="$JAVA"; b=`basename "$file" .java`; args="$b $args";;
      *.sh) prog="/bin/sh"; args="$file $args";;
    esac
    echo "Content-type: text/html\n
      <html><head><title>VECR/IO</title></head><body bgcolor=white text=black>
      <b>${user} - ${COURSE}
      - <a href=\"/prog/${COURSE}?edit+${sub}+${file}\">${sub}/${file}</a>
      - <a href=\"/prog/${COURSE}?edit+${sub}\">${sub}</a>
      - <a href=\"/prog/${COURSE}\">Home</a></b>
      - Running: $prog $args
      <br><applet codebase=\"/vecr/IO\" code=\"IOapplet.class\" width=700 height=600>"
    cd "/vecr/IO/bin" || exit 1
    $JAVA IOticket "$user" "$uid"
    echo "<param name=\"dir\" value=\"$dir/$sub\">
      <param name=\"prog\" value=\"${prog}\">
      <param name=\"args\" value=\"${args}\">
      Your browser does not support Java, or Java is not enabled.  Sorry!
      </applet></body></html>"
    exit 0
    ;;
Note the use of IOticket.java, which takes the UserID and numerical uid and creates a ticket:
    SecretKeySpec KS = new SecretKeySpec( secret, "HmacSHA256");
    Mac mac = Mac.getInstance( "HmacSHA256");
    mac.init( KS);

    String time = Long.toString(System.currentTimeMillis());

    mac.update( time.getBytes());
    mac.update( user.getBytes());
    mac.update( uid.getBytes());

    String ticket = hex( mac.doFinal());

    System.out.println( "<param name=\"user\" value=\"" + user + "\">");
    System.out.println( "<param name=\"uid\" value=\"" + uid + "\">");
    System.out.println( "<param name=\"time\" value=\"" + time + "\">");
    System.out.println( "<param name=\"ticket\" value=\"" + ticket + "\">");
Note that the ticket includes the current time; this is checked on the server so that a ticket only remains valid for 10 minutes:
     // check authentication ticket time limit
     //
      long mytime = System.currentTimeMillis();
      long yourtime = Long.parseLong( time);

      if( mytime - yourtime > 600000) // 10 minute limit
      {
        out.write( "Authentication data is too old\n".getBytes());
        out.flush();
        throw new SecurityException(
          "Stale authentication data for user " + user + " from " + name);
      }
The authentication data, as well as the user directory, program to run, and command-line arguments, are obtained by the applet from parameters passed in the generated IO web page, for example:
<applet codebase="/vecr/IO" code="IOapplet.class" width=700 height=600>
<param name="user" value="frodo">
<param name="uid" value="3001">
<param name="time" value="1108241035769">
<param name="ticket" value="a43c774caf9abdaaebc3c33cae9325aa1bc79c01b78757e3174ebb5006084844">
<param name="dir" value="/vecr/fc/home/frodo/a4">
<param name="prog" value="./p1">
<param name="args" value="">
When the applet starts, it sends all of that data to the server:
      // send authentication data
      //
      String user = getParameter( "user");
      diag.append( "* Sending authentication data for ");
      diag.append( user);
      diag.append( newline);

      out.writeUTF( user);
      out.writeUTF( getParameter( "uid"));
      out.writeUTF( getParameter( "time"));
      out.writeUTF( getParameter( "ticket"));
      out.writeUTF( getParameter( "dir"));
      out.writeUTF( getParameter( "prog"));
      out.writeUTF( getParameter( "args"));
      out.flush();
Authentication consists of verifying the ticket (and checking that it is not too old which was shown above):
     // construct authentication data
     //
      SecretKeySpec KS = new SecretKeySpec( secret, "HmacSHA256");
      Mac mac = Mac.getInstance( "HmacSHA256");
      mac.init( KS);

      mac.update( time.getBytes());
      mac.update( user.getBytes());
      mac.update( uid.getBytes());
      String auth = hex( mac.doFinal());

      if( auth.compareTo( ticket) != 0) // client authentication ticket is invalid
      {
        out.write( "Authentication failed\n".getBytes());
        out.flush();
        throw new SecurityException(
          "Authentication failed for user " + user + " from " + name);
      }
Since the user was already known to be authenticated at the time the IO option was initiated, the ticket allows that authentication to propagate from the applet to the server without having the user resend their userid and password.

Security Issues

  1. Problems with 10 minute time limit? Maybe should be 1 second limit?

    The applet web page can be downloaded, saved, modified, uploaded, given to another user, etc.

  2. Problems with the secret used in the ticket hash?

    The secret is created/recreated periodically like this:

     dd if=/dev/random ibs=1 obs=1 count=64 > secret.dat
    
    The directory and file are protected:
    % ls -ld . secret.dat
    drwxr-x---   2 root     root         512 Feb 13 11:02 .
    -rw-------   1 root     root          64 Feb 13 11:35 secret.dat
    
    The secret.dat file is read as follows:
         // read secret data
         //
          FileInputStream fin = new FileInputStream( "/vecr/IO/bin/secret.dat");
          byte secret[] = new byte[64];
          int n = fin.read( secret);
          fin.close();
    
          if( n < 64)
            throw new SecurityException( "secret.dat is too small");
    
  3. The directory and program to run are not included in the ticket hash and can be faked or altered. Is that a problem?