4343import java .security .MessageDigest ;
4444import java .security .SecureRandom ;
4545import java .util .Base64 ;
46+ import java .util .concurrent .ConcurrentHashMap ;
47+ import java .util .concurrent .TimeUnit ;
4648import javax .crypto .Cipher ;
4749import javax .crypto .spec .GCMParameterSpec ;
4850import javax .crypto .spec .SecretKeySpec ;
@@ -71,6 +73,10 @@ public class SessionIdHeaderFilter extends OncePerRequestFilter {
7173 private static final String CIPHER_ALGO = "AES/GCM/NoPadding" ;
7274 private static final String HASH_ALGO = "SHA-256" ;
7375 private static final int KEY_LENGTH_BYTES = 32 ;
76+ private static final long CACHE_TTL_MILLIS = TimeUnit .MINUTES .toMillis (5 );
77+ private static final int MAX_CACHE_SIZE = 10_000 ;
78+ private static final ConcurrentHashMap <String , CacheEntry > HEADER_CACHE =
79+ new ConcurrentHashMap <>();
7480
7581 private final boolean enabled ;
7682 private final byte [] keyBytes ;
@@ -107,8 +113,10 @@ protected void doFilterInternal(
107113 UserDetails userDetails = CurrentUserUtil .getCurrentUserDetails ();
108114 HttpSession session = request .getSession (false );
109115 if (session != null ) {
110- String payload = userDetails .getUid () + ":" + hashSessionId (session .getId ());
111- response .addHeader (HEADER_NAME , encrypt (payload ));
116+ String sessionHash = hashSessionId (session .getId ());
117+ String cacheKey = userDetails .getUid () + ":" + sessionHash ;
118+ String headerValue = getOrCreateHeaderValue (cacheKey );
119+ response .addHeader (HEADER_NAME , headerValue );
112120 }
113121 } catch (GeneralSecurityException ex ) {
114122 log .error ("Failed to encrypt session header payload" , ex );
@@ -130,6 +138,31 @@ private String encrypt(String payload) throws GeneralSecurityException {
130138 return HEADER_VERSION_PREFIX + Base64 .getUrlEncoder ().withoutPadding ().encodeToString (combined );
131139 }
132140
141+ private String getOrCreateHeaderValue (String cacheKey ) throws GeneralSecurityException {
142+ long now = System .currentTimeMillis ();
143+ CacheEntry cached = HEADER_CACHE .get (cacheKey );
144+ if (cached != null && cached .expiresAtMillis > now ) {
145+ return cached .headerValue ;
146+ }
147+
148+ if (cached != null ) {
149+ HEADER_CACHE .remove (cacheKey , cached );
150+ }
151+
152+ String headerValue = encrypt (cacheKey );
153+ CacheEntry entry = new CacheEntry (headerValue , now + CACHE_TTL_MILLIS );
154+ HEADER_CACHE .put (cacheKey , entry );
155+
156+ if (HEADER_CACHE .size () > MAX_CACHE_SIZE ) {
157+ HEADER_CACHE .entrySet ().removeIf (e -> e .getValue ().expiresAtMillis <= now );
158+ if (HEADER_CACHE .size () > MAX_CACHE_SIZE ) {
159+ HEADER_CACHE .clear ();
160+ }
161+ }
162+
163+ return headerValue ;
164+ }
165+
133166 private static byte [] decodeKey (String token ) {
134167 try {
135168 return Base64 .getDecoder ().decode (token );
@@ -143,4 +176,6 @@ private static String hashSessionId(String sessionId) throws GeneralSecurityExce
143176 byte [] hashed = digest .digest (sessionId .getBytes (StandardCharsets .UTF_8 ));
144177 return Base64 .getUrlEncoder ().withoutPadding ().encodeToString (hashed );
145178 }
179+
180+ private record CacheEntry (String headerValue , long expiresAtMillis ) {}
146181}
0 commit comments