disable fingerpritning

This commit is contained in:
Anthony Stirling 2024-10-05 09:15:43 +01:00
parent c59d3ff3e0
commit 3b5b7772a9
3 changed files with 279 additions and 279 deletions

View File

@ -1,68 +1,68 @@
package stirling.software.SPDF.config.fingerprint; //package stirling.software.SPDF.config.fingerprint;
//
import java.io.IOException; //import java.io.IOException;
//
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; //import org.springframework.web.filter.OncePerRequestFilter;
//
import jakarta.servlet.FilterChain; //import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; //import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; //import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; //import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession; //import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j; //import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.RequestUriUtils; //import stirling.software.SPDF.utils.RequestUriUtils;
//
@Component ////@Component
@Slf4j //@Slf4j
public class FingerprintBasedSessionFilter extends OncePerRequestFilter { //public class FingerprintBasedSessionFilter extends OncePerRequestFilter {
private final FingerprintGenerator fingerprintGenerator; // private final FingerprintGenerator fingerprintGenerator;
private final FingerprintBasedSessionManager sessionManager; // private final FingerprintBasedSessionManager sessionManager;
//
@Autowired // @Autowired
public FingerprintBasedSessionFilter( // public FingerprintBasedSessionFilter(
FingerprintGenerator fingerprintGenerator, // FingerprintGenerator fingerprintGenerator,
FingerprintBasedSessionManager sessionManager) { // FingerprintBasedSessionManager sessionManager) {
this.fingerprintGenerator = fingerprintGenerator; // this.fingerprintGenerator = fingerprintGenerator;
this.sessionManager = sessionManager; // this.sessionManager = sessionManager;
} // }
//
@Override // @Override
protected void doFilterInternal( // protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) // HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { // throws ServletException, IOException {
//
if (RequestUriUtils.isStaticResource(request.getContextPath(), request.getRequestURI())) { // if (RequestUriUtils.isStaticResource(request.getContextPath(), request.getRequestURI())) {
filterChain.doFilter(request, response); // filterChain.doFilter(request, response);
return; // return;
} // }
//
String fingerprint = fingerprintGenerator.generateFingerprint(request); // String fingerprint = fingerprintGenerator.generateFingerprint(request);
log.debug("Generated fingerprint for request: {}", fingerprint); // log.debug("Generated fingerprint for request: {}", fingerprint);
//
HttpSession session = request.getSession(); // HttpSession session = request.getSession();
boolean isNewSession = session.isNew(); // boolean isNewSession = session.isNew();
String sessionId = session.getId(); // String sessionId = session.getId();
//
if (isNewSession) { // if (isNewSession) {
log.info("New session created: {}", sessionId); // log.info("New session created: {}", sessionId);
} // }
//
if (!sessionManager.isFingerPrintAllowed(fingerprint)) { // if (!sessionManager.isFingerPrintAllowed(fingerprint)) {
log.info("Blocked fingerprint detected, redirecting: {}", fingerprint); // log.info("Blocked fingerprint detected, redirecting: {}", fingerprint);
response.sendRedirect(request.getContextPath() + "/too-many-requests"); // response.sendRedirect(request.getContextPath() + "/too-many-requests");
return; // return;
} // }
//
session.setAttribute("userFingerprint", fingerprint); // session.setAttribute("userFingerprint", fingerprint);
session.setAttribute( // session.setAttribute(
FingerprintBasedSessionManager.STARTUP_TIMESTAMP, // FingerprintBasedSessionManager.STARTUP_TIMESTAMP,
FingerprintBasedSessionManager.APP_STARTUP_TIME); // FingerprintBasedSessionManager.APP_STARTUP_TIME);
//
sessionManager.registerFingerprint(fingerprint, sessionId); // sessionManager.registerFingerprint(fingerprint, sessionId);
//
log.debug("Proceeding with request: {}", request.getRequestURI()); // log.debug("Proceeding with request: {}", request.getRequestURI());
filterChain.doFilter(request, response); // filterChain.doFilter(request, response);
} // }
} //}

View File

@ -1,134 +1,134 @@
package stirling.software.SPDF.config.fingerprint; //package stirling.software.SPDF.config.fingerprint;
//
import java.util.Iterator; //import java.util.Iterator;
import java.util.Map; //import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; //import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; //import java.util.concurrent.TimeUnit;
//
import org.springframework.scheduling.annotation.Scheduled; //import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
//
import jakarta.servlet.http.HttpSession; //import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionAttributeListener; //import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionEvent; //import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener; //import jakarta.servlet.http.HttpSessionListener;
import lombok.AllArgsConstructor; //import lombok.AllArgsConstructor;
import lombok.Data; //import lombok.Data;
import lombok.extern.slf4j.Slf4j; //import lombok.extern.slf4j.Slf4j;
//
@Slf4j //@Slf4j
@Component //@Component
public class FingerprintBasedSessionManager //public class FingerprintBasedSessionManager
implements HttpSessionListener, HttpSessionAttributeListener { // implements HttpSessionListener, HttpSessionAttributeListener {
private static final ConcurrentHashMap<String, FingerprintInfo> activeFingerprints = // private static final ConcurrentHashMap<String, FingerprintInfo> activeFingerprints =
new ConcurrentHashMap<>(); // new ConcurrentHashMap<>();
//
// To be reduced in later version to 8~ // // To be reduced in later version to 8~
private static final int MAX_ACTIVE_FINGERPRINTS = 30; // private static final int MAX_ACTIVE_FINGERPRINTS = 30;
//
static final String STARTUP_TIMESTAMP = "appStartupTimestamp"; // static final String STARTUP_TIMESTAMP = "appStartupTimestamp";
static final long APP_STARTUP_TIME = System.currentTimeMillis(); // static final long APP_STARTUP_TIME = System.currentTimeMillis();
private static final long FINGERPRINT_EXPIRATION = TimeUnit.MINUTES.toMillis(30); // private static final long FINGERPRINT_EXPIRATION = TimeUnit.MINUTES.toMillis(30);
//
@Override // @Override
public void sessionCreated(HttpSessionEvent se) { // public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession(); // HttpSession session = se.getSession();
String sessionId = session.getId(); // String sessionId = session.getId();
String fingerprint = (String) session.getAttribute("userFingerprint"); // String fingerprint = (String) session.getAttribute("userFingerprint");
//
if (fingerprint == null) { // if (fingerprint == null) {
log.warn("Session created without fingerprint: {}", sessionId); // log.warn("Session created without fingerprint: {}", sessionId);
return; // return;
} // }
//
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
if (activeFingerprints.size() >= MAX_ACTIVE_FINGERPRINTS // if (activeFingerprints.size() >= MAX_ACTIVE_FINGERPRINTS
&& !activeFingerprints.containsKey(fingerprint)) { // && !activeFingerprints.containsKey(fingerprint)) {
log.info("Max fingerprints reached. Marking session as blocked: {}", sessionId); // log.info("Max fingerprints reached. Marking session as blocked: {}", sessionId);
session.setAttribute("blocked", true); // session.setAttribute("blocked", true);
} else { // } else {
activeFingerprints.put( // activeFingerprints.put(
fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis())); // fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
log.info( // log.info(
"New fingerprint registered: {}. Total active fingerprints: {}", // "New fingerprint registered: {}. Total active fingerprints: {}",
fingerprint, // fingerprint,
activeFingerprints.size()); // activeFingerprints.size());
} // }
session.setAttribute(STARTUP_TIMESTAMP, APP_STARTUP_TIME); // session.setAttribute(STARTUP_TIMESTAMP, APP_STARTUP_TIME);
} // }
} // }
//
@Override // @Override
public void sessionDestroyed(HttpSessionEvent se) { // public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession(); // HttpSession session = se.getSession();
String fingerprint = (String) session.getAttribute("userFingerprint"); // String fingerprint = (String) session.getAttribute("userFingerprint");
//
if (fingerprint != null) { // if (fingerprint != null) {
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
activeFingerprints.remove(fingerprint); // activeFingerprints.remove(fingerprint);
log.info( // log.info(
"Fingerprint removed: {}. Total active fingerprints: {}", // "Fingerprint removed: {}. Total active fingerprints: {}",
fingerprint, // fingerprint,
activeFingerprints.size()); // activeFingerprints.size());
} // }
} // }
} // }
//
public boolean isFingerPrintAllowed(String fingerprint) { // public boolean isFingerPrintAllowed(String fingerprint) {
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
return activeFingerprints.size() < MAX_ACTIVE_FINGERPRINTS // return activeFingerprints.size() < MAX_ACTIVE_FINGERPRINTS
|| activeFingerprints.containsKey(fingerprint); // || activeFingerprints.containsKey(fingerprint);
} // }
} // }
//
public void registerFingerprint(String fingerprint, String sessionId) { // public void registerFingerprint(String fingerprint, String sessionId) {
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
activeFingerprints.put( // activeFingerprints.put(
fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis())); // fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
} // }
} // }
//
public void unregisterFingerprint(String fingerprint) { // public void unregisterFingerprint(String fingerprint) {
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
activeFingerprints.remove(fingerprint); // activeFingerprints.remove(fingerprint);
} // }
} // }
//
@Scheduled(fixedRate = 1800000) // Run every 30 mins // @Scheduled(fixedRate = 1800000) // Run every 30 mins
public void cleanupStaleFingerprints() { // public void cleanupStaleFingerprints() {
log.info("Starting cleanup of stale fingerprints"); // log.info("Starting cleanup of stale fingerprints");
long now = System.currentTimeMillis(); // long now = System.currentTimeMillis();
int removedCount = 0; // int removedCount = 0;
//
synchronized (activeFingerprints) { // synchronized (activeFingerprints) {
Iterator<Map.Entry<String, FingerprintInfo>> iterator = // Iterator<Map.Entry<String, FingerprintInfo>> iterator =
activeFingerprints.entrySet().iterator(); // activeFingerprints.entrySet().iterator();
while (iterator.hasNext()) { // while (iterator.hasNext()) {
Map.Entry<String, FingerprintInfo> entry = iterator.next(); // Map.Entry<String, FingerprintInfo> entry = iterator.next();
FingerprintInfo info = entry.getValue(); // FingerprintInfo info = entry.getValue();
//
if (now - info.getLastAccessTime() > FINGERPRINT_EXPIRATION) { // if (now - info.getLastAccessTime() > FINGERPRINT_EXPIRATION) {
iterator.remove(); // iterator.remove();
removedCount++; // removedCount++;
log.info("Removed stale fingerprint: {}", entry.getKey()); // log.info("Removed stale fingerprint: {}", entry.getKey());
} // }
} // }
} // }
//
log.info("Cleanup complete. Removed {} stale fingerprints", removedCount); // log.info("Cleanup complete. Removed {} stale fingerprints", removedCount);
} // }
//
public void updateLastAccessTime(String fingerprint) { // public void updateLastAccessTime(String fingerprint) {
FingerprintInfo info = activeFingerprints.get(fingerprint); // FingerprintInfo info = activeFingerprints.get(fingerprint);
if (info != null) { // if (info != null) {
info.setLastAccessTime(System.currentTimeMillis()); // info.setLastAccessTime(System.currentTimeMillis());
} // }
} // }
//
@Data // @Data
@AllArgsConstructor // @AllArgsConstructor
private static class FingerprintInfo { // private static class FingerprintInfo {
private String sessionId; // private String sessionId;
private long lastAccessTime; // private long lastAccessTime;
} // }
} //}

View File

@ -1,77 +1,77 @@
package stirling.software.SPDF.config.fingerprint; //package stirling.software.SPDF.config.fingerprint;
//
import java.security.MessageDigest; //import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; //import java.security.NoSuchAlgorithmException;
//
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
//
import jakarta.servlet.http.HttpServletRequest; //import jakarta.servlet.http.HttpServletRequest;
//
@Component //@Component
public class FingerprintGenerator { //public class FingerprintGenerator {
//
public String generateFingerprint(HttpServletRequest request) { // public String generateFingerprint(HttpServletRequest request) {
if (request == null) { // if (request == null) {
return ""; // return "";
} // }
StringBuilder fingerprintBuilder = new StringBuilder(); // StringBuilder fingerprintBuilder = new StringBuilder();
//
// Add IP address // // Add IP address
fingerprintBuilder.append(request.getRemoteAddr()); // fingerprintBuilder.append(request.getRemoteAddr());
//
// Add X-Forwarded-For header if present (for clients behind proxies) // // Add X-Forwarded-For header if present (for clients behind proxies)
String forwardedFor = request.getHeader("X-Forwarded-For"); // String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null) { // if (forwardedFor != null) {
fingerprintBuilder.append(forwardedFor); // fingerprintBuilder.append(forwardedFor);
} // }
//
// Add User-Agent // // Add User-Agent
String userAgent = request.getHeader("User-Agent"); // String userAgent = request.getHeader("User-Agent");
if (userAgent != null) { // if (userAgent != null) {
fingerprintBuilder.append(userAgent); // fingerprintBuilder.append(userAgent);
} // }
//
// Add Accept-Language header // // Add Accept-Language header
String acceptLanguage = request.getHeader("Accept-Language"); // String acceptLanguage = request.getHeader("Accept-Language");
if (acceptLanguage != null) { // if (acceptLanguage != null) {
fingerprintBuilder.append(acceptLanguage); // fingerprintBuilder.append(acceptLanguage);
} // }
//
// Add Accept header // // Add Accept header
String accept = request.getHeader("Accept"); // String accept = request.getHeader("Accept");
if (accept != null) { // if (accept != null) {
fingerprintBuilder.append(accept); // fingerprintBuilder.append(accept);
} // }
//
// Add Connection header // // Add Connection header
String connection = request.getHeader("Connection"); // String connection = request.getHeader("Connection");
if (connection != null) { // if (connection != null) {
fingerprintBuilder.append(connection); // fingerprintBuilder.append(connection);
} // }
//
// Add server port // // Add server port
fingerprintBuilder.append(request.getServerPort()); // fingerprintBuilder.append(request.getServerPort());
//
// Add secure flag // // Add secure flag
fingerprintBuilder.append(request.isSecure()); // fingerprintBuilder.append(request.isSecure());
//
// Generate a hash of the fingerprint // // Generate a hash of the fingerprint
return generateHash(fingerprintBuilder.toString()); // return generateHash(fingerprintBuilder.toString());
} // }
//
private String generateHash(String input) { // private String generateHash(String input) {
try { // try {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); // MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes()); // byte[] hash = digest.digest(input.getBytes());
StringBuilder hexString = new StringBuilder(); // StringBuilder hexString = new StringBuilder();
for (byte b : hash) { // for (byte b : hash) {
String hex = Integer.toHexString(0xff & b); // String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0'); // if (hex.length() == 1) hexString.append('0');
hexString.append(hex); // hexString.append(hex);
} // }
return hexString.toString(); // return hexString.toString();
} catch (NoSuchAlgorithmException e) { // } catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to generate fingerprint hash", e); // throw new RuntimeException("Failed to generate fingerprint hash", e);
} // }
} // }
} //}