001/* 002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.http.security.pipeline; 017 018import de.cuioss.http.security.config.SecurityConfiguration; 019import de.cuioss.http.security.core.HttpSecurityValidator; 020import de.cuioss.http.security.core.ValidationType; 021import de.cuioss.http.security.monitoring.SecurityEventCounter; 022import de.cuioss.http.security.validation.CharacterValidationStage; 023import de.cuioss.http.security.validation.LengthValidationStage; 024import de.cuioss.http.security.validation.NormalizationStage; 025import de.cuioss.http.security.validation.PatternMatchingStage; 026import lombok.EqualsAndHashCode; 027import lombok.Getter; 028import lombok.ToString; 029 030import java.util.List; 031import java.util.Objects; 032 033/** 034 * Sequential validation pipeline specifically for HTTP header components. 035 * 036 * <h3>Validation Sequence</h3> 037 * <ol> 038 * <li><strong>Length Validation</strong> - Enforces maximum header length limits</li> 039 * <li><strong>Character Validation</strong> - Validates RFC 7230 header characters</li> 040 * <li><strong>Normalization</strong> - Header normalization and security checks</li> 041 * <li><strong>Pattern Matching</strong> - Detects injection attacks and suspicious patterns</li> 042 * </ol> 043 * 044 * <h3>Design Principles</h3> 045 * <ul> 046 * <li><strong>Sequential Execution</strong> - Each stage processes the output of the previous stage</li> 047 * <li><strong>Early Termination</strong> - Pipeline stops on first security violation</li> 048 * <li><strong>Security First</strong> - Validates before any transformation</li> 049 * <li><strong>Immutable</strong> - Thread-safe pipeline instance</li> 050 * </ul> 051 * 052 * <h3>HTTP Header Security</h3> 053 * <ul> 054 * <li><strong>Header Injection Prevention</strong> - Detects CRLF injection attempts</li> 055 * <li><strong>RFC 7230 Compliance</strong> - Enforces HTTP header character restrictions</li> 056 * <li><strong>Length Limits</strong> - Prevents header-based DoS attacks</li> 057 * <li><strong>Pattern Detection</strong> - Identifies malicious header values</li> 058 * </ul> 059 * 060 * <h3>Usage Example</h3> 061 * <pre> 062 * SecurityConfiguration config = SecurityConfiguration.defaults(); 063 * SecurityEventCounter counter = new SecurityEventCounter(); 064 * 065 * HTTPHeaderValidationPipeline pipeline = new HTTPHeaderValidationPipeline(config, counter); 066 * 067 * try { 068 * String safeHeader = pipeline.validate("Bearer eyJhbGciOiJIUzI1NiJ9..."); 069 * // Use safeHeader for processing 070 * } catch (UrlSecurityException e) { 071 * // Handle security violation 072 * log.warn("Header validation failed: {}", e.getMessage()); 073 * } 074 * </pre> 075 * 076 * Implements: Task P3 from HTTP verification specification 077 * 078 * @since 1.0 079 */ 080@EqualsAndHashCode(callSuper = false, of = {"validationType"}) 081@ToString(callSuper = true) 082@Getter 083public final class HTTPHeaderValidationPipeline extends AbstractValidationPipeline { 084 085 private final ValidationType validationType; 086 087 /** 088 * Creates a new HTTP header validation pipeline with the specified configuration. 089 * The pipeline can be configured for either header names or header values. 090 * 091 * @param config The security configuration to use 092 * @param eventCounter The counter for tracking security events 093 * @param validationType The type of header component to validate (HEADER_NAME or HEADER_VALUE) 094 * @throws NullPointerException if config, eventCounter, or validationType is null 095 * @throws IllegalArgumentException if validationType is not a header type 096 */ 097 public HTTPHeaderValidationPipeline(SecurityConfiguration config, 098 SecurityEventCounter eventCounter, 099 ValidationType validationType) { 100 super(createStages(config, validationType), Objects.requireNonNull(eventCounter, "EventCounter must not be null")); 101 Objects.requireNonNull(validationType, "ValidationType must not be null"); 102 103 if (!validationType.isHeader()) { 104 throw new IllegalArgumentException("ValidationType must be a header type, got: " + validationType); 105 } 106 107 this.validationType = validationType; 108 } 109 110 private static List<HttpSecurityValidator> createStages(SecurityConfiguration config, ValidationType validationType) { 111 Objects.requireNonNull(config, "Config must not be null"); 112 Objects.requireNonNull(validationType, "ValidationType must not be null"); 113 114 // Create validation stages in the correct order for HTTP headers 115 // Note: Headers typically don't need URL decoding, so we skip DecodingStage 116 return List.of( 117 new LengthValidationStage(config, validationType), 118 new CharacterValidationStage(config, validationType), 119 new NormalizationStage(config, validationType), 120 new PatternMatchingStage(config, validationType) 121 ); 122 } 123 124 @Override 125 public ValidationType getValidationType() { 126 return validationType; 127 } 128 129}