You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/01/30 15:21:12 UTC
svn commit: r739288 -
/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java
Author: matzew
Date: Fri Jan 30 14:21:12 2009
New Revision: 739288
URL: http://svn.apache.org/viewvc?rev=739288&view=rev
Log:
TRINIDAD-1375 - Increase strength of viewState token
thanks to Blake Sullivan for the patch
Modified:
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java?rev=739288&r1=739287&r2=739288&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java Fri Jan 30 14:21:12 2009
@@ -18,19 +18,22 @@
*/
package org.apache.myfaces.trinidadinternal.util;
-import java.io.IOException;
-import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.math.BigInteger;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
-import javax.servlet.http.HttpSession;
-
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -80,19 +83,8 @@
cache = (TokenCache) external.getSessionMap().get(cacheName);
if ((cache == null) && createIfNeeded)
{
- // Seed the token cache with the session ID (if available)
- int seed = 0;
- if (_USE_SESSION_TO_SEED_ID)
- {
- if (session instanceof HttpSession)
- {
- String id = ((HttpSession) session).getId();
- if (id != null)
- seed = id.hashCode();
- }
- }
-
- cache = new TokenCache(defaultSize, seed);
+ // create the TokenCache with the crytographically random seed
+ cache = new TokenCache(defaultSize, _getSeed());
external.getSessionMap().put(cacheName, cache);
}
@@ -100,6 +92,33 @@
return cache;
}
+
+ /**
+ * Returns a cryptographically secure random number to use as the TokenCache seed
+ */
+ private static long _getSeed()
+ {
+ SecureRandom rng;
+
+ try
+ {
+ // try SHA1 first
+ rng = SecureRandom.getInstance("SHA1PRNG");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // SHA1 not present, so try the default (which could potentially not be
+ // cryptographically secure)
+ rng = new SecureRandom();
+ }
+
+ // use 48 bits for strength and fill them in
+ byte[] randomBytes = new byte[6];
+ rng.nextBytes(randomBytes);
+
+ // convert to a long
+ return new BigInteger(randomBytes).longValue();
+ }
/**
@@ -107,28 +126,42 @@
*/
public TokenCache()
{
- this(_DEFAULT_SIZE, 0);
+ this(_DEFAULT_SIZE, 0L);
}
/**
- * Create a TokenCache that will store the last "size" entries.
+ * Create a TokenCache that will store the last "size" entries. This version should
+ * not be used if the token cache is externally accessible (since the seed always
+ * starts at 0). Use the
+ * constructor with the long seed instead.
*/
public TokenCache(int size)
{
- this(size, 0);
+ this(size, 0L);
}
/**
* Create a TokenCache that will store the last "size" entries,
* and begins its tokens based on the seed (instead of always
* starting at "0").
+ * @Deprecated Use version using a long size instead for greater security
*/
public TokenCache(int size, int seed)
{
+ this(size, (long)seed);
+ }
+
+ /**
+ * Create a TokenCache that will store the last "size" entries,
+ * and begins its tokens based on the seed (instead of always
+ * starting at "0").
+ */
+ public TokenCache(int size, long seed)
+ {
_cache = new LRU(size);
_pinned = new ConcurrentHashMap<String, String>(size);
- _count = seed;
+ _count = new AtomicLong(seed);
}
/**
@@ -285,19 +318,11 @@
private String _getNextToken()
{
- synchronized (_lock)
- {
- _count = _count + 1;
- return Integer.toString(_count, 16);
- }
- }
-
- private void readObject(ObjectInputStream in)
- throws ClassNotFoundException, IOException
- {
- in.defaultReadObject();
- // Re-create the lock, which was transient
- _lock = new Object();
+ // atomically increment the value
+ long nextToken = _count.incrementAndGet();
+
+ // convert using base 36 because it is a fast efficient subset of base-64
+ return Long.toString(nextToken, 36);
}
private class LRU extends LRUCache<String, String>
@@ -322,15 +347,14 @@
// stored, and the values are the tokens that are pinned. This is
// an N->1 ratio: the values may appear multiple times.
private final Map<String, String> _pinned;
- private int _count;
- private transient Object _lock = new Object();
+
+ // the current token value
+ private final AtomicLong _count;
// Hack instance parameter used to communicate between the LRU cache's
// removing() method, and the addNewEntry() method that may trigger it
private transient String _removed;
- static private final boolean _USE_SESSION_TO_SEED_ID = true;
-
static private final int _DEFAULT_SIZE = 15;
static private final long serialVersionUID = 1L;
static private final TrinidadLogger _LOG =