A proteção contra ataques de injeção de SQL em aplicações web desanvolvidas com o framework Struts2 pode ser implementada de forma centralizada através do uso de interceptadores (interceptors). Essa abordagem permite validar e sanitizar os parâmetros de requisição entes que eles alcancem as camadas de controle e persistência.
Para configurar essa validação, é necessário registrar o interceptador personalizado no arquivo de configuração do Struts (struts.xml) e associá-lo a uma pilha de itnerceptadores (interceptor stack).
<interceptors>
<interceptor name="securityValidator" class="com.app.security.SqlInjectionInterceptor"/>
<interceptor-stack name="secureStack">
<interceptor-ref name="securityValidator"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
A implementação do interceptador em Java deve estender AbstractInterceptor para simplificar o ciclo de vida do componente. A lógica principal consiste em verificar a sessão do usuário, extrair os parâmetros da requisição, aplicar decodificação de URL para evitar técnicas de evasão e validar o conteúdo contra uma expressão regular que identifica caracteres especiais potencialmente maliciosos.
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import org.apache.struts2.StrutsStatics;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SqlInjectionInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
// Expressão regular para detectar caracteres especiais potencialmente maliciosos
private static final String SPECIAL_CHARS_REGEX = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:""’。,、?]";
private static final Pattern THREAT_PATTERN = Pattern.compile(SPECIAL_CHARS_REGEX);
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// Verifica se o usuário está autenticado
UserSession currentUser = SecurityContext.getCurrentSession();
if (currentUser == null) {
return "login";
}
ActionContext context = invocation.getInvocationContext();
HttpServletRequest httpRequest = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
httpRequest.setCharacterEncoding(StandardCharsets.UTF_8.name());
Map<String, Object> requestParams = context.getParameters();
boolean isThreatDetected = false;
for (Map.Entry<String, Object> paramEntry : requestParams.entrySet()) {
String[] paramValues = (String[]) paramEntry.getValue();
if (paramValues != null && paramValues.length > 0 && paramValues[0] != null && !paramValues[0].trim().isEmpty()) {
// Dupla decodificação de URL para prevenir técnicas de bypass
String decodedValue = URLDecoder.decode(paramValues[0], StandardCharsets.UTF_8.name());
decodedValue = URLDecoder.decode(decodedValue, StandardCharsets.UTF_8.name());
Matcher matcher = THREAT_PATTERN.matcher(decodedValue);
if (matcher.find()) {
isThreatDetected = true;
break;
}
}
}
if (isThreatDetected) {
// Bloqueia a requisição se caracteres maliciosos forem encontrados
return "security_error";
}
// Prossegue com a execução da ação
return invocation.invoke();
}
}
Neste exemplo, a expressão regular SPECIAL_CHARS_REGEX atua como uma lista de bloqueio para símbolos comumente utilizados em payloads de injeção. A dupla decodificação (URLDecoder.decode) é uma medida defensiva crucial, pois atacantes frequentemente codificam caracteres maliciosos múltiplas vezes para contornar filtros de segurança superficiais. Caso a validação falhe, a execução da ação é interrompida e o fluxo é redirecionado para um resultado de erro de segurança.