001package com.streamconverter.security; 002 003import java.io.InputStream; 004import javax.xml.XMLConstants; 005import javax.xml.parsers.DocumentBuilder; 006import javax.xml.parsers.DocumentBuilderFactory; 007import javax.xml.parsers.ParserConfigurationException; 008import javax.xml.stream.XMLInputFactory; 009import javax.xml.transform.TransformerFactory; 010import javax.xml.validation.SchemaFactory; 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014/** 015 * XML処理のセキュリティ設定を提供するユーティリティクラス 016 * 017 * <p>このクラスは、XXE(XML外部エンティティ)攻撃や その他のXML関連のセキュリティ脆弱性を防ぐため、 安全なXML処理設定を提供します。 018 * 019 * <p>主な機能: 020 * 021 * <ul> 022 * <li>XXE攻撃防止のためのDocumentBuilderFactory設定 023 * <li>安全なXMLInputFactory設定 024 * <li>安全なTransformerFactory設定 025 * <li>安全なSchemaFactory設定 026 * <li>セキュリティ設定の動的調整 027 * </ul> 028 * 029 * @since 1.0.0 030 */ 031public class SecureXmlConfiguration { 032 033 private static final Logger logger = LoggerFactory.getLogger(SecureXmlConfiguration.class); 034 private static final Logger securityLogger = 035 LoggerFactory.getLogger("com.streamConverter.security"); 036 037 private SecureXmlConfiguration() { 038 // ユーティリティクラスのため、インスタンス化を禁止 039 } 040 041 /** 042 * XXE攻撃を防ぐように設定されたDocumentBuilderFactoryを作成します 043 * 044 * @return 安全に設定されたDocumentBuilderFactory 045 * @throws ParserConfigurationException 設定に失敗した場合 046 */ 047 public static DocumentBuilderFactory createSecureDocumentBuilderFactory() 048 throws ParserConfigurationException { 049 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 050 051 // XXE攻撃防止設定 052 try { 053 // DOCTYPE宣言を無効化 054 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 055 securityLogger.debug("DOCTYPE declarations disabled"); 056 } catch (ParserConfigurationException e) { 057 logger.warn("Failed to disable DOCTYPE declarations", e); 058 } 059 060 try { 061 // 外部一般エンティティを無効化 062 factory.setFeature("http://xml.org/sax/features/external-general-entities", false); 063 // 外部パラメータエンティティを無効化 064 factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); 065 securityLogger.debug("External entities disabled"); 066 } catch (ParserConfigurationException e) { 067 logger.warn("Failed to disable external entities", e); 068 } 069 070 // 追加のセキュリティ設定 071 factory.setNamespaceAware(true); 072 factory.setValidating(false); 073 074 // XMLリーダーのセキュリティ制限 075 factory.setXIncludeAware(false); 076 factory.setExpandEntityReferences(false); 077 078 securityLogger.info("Secure DocumentBuilderFactory created with XXE protection"); 079 return factory; 080 } 081 082 /** 083 * 安全に設定されたDocumentBuilderを作成します 084 * 085 * @return 安全に設定されたDocumentBuilder 086 * @throws ParserConfigurationException 設定に失敗した場合 087 */ 088 public static DocumentBuilder createSecureDocumentBuilder() throws ParserConfigurationException { 089 DocumentBuilderFactory factory = createSecureDocumentBuilderFactory(); 090 return factory.newDocumentBuilder(); 091 } 092 093 /** 094 * XXE攻撃を防ぐように設定されたXMLInputFactoryを作成します 095 * 096 * @return 安全に設定されたXMLInputFactory 097 */ 098 public static XMLInputFactory createSecureXMLInputFactory() { 099 XMLInputFactory factory = XMLInputFactory.newInstance(); 100 101 // 外部エンティティの処理を無効化 102 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); 103 factory.setProperty(XMLInputFactory.SUPPORT_DTD, false); 104 105 // 追加のセキュリティ設定 106 factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); 107 factory.setProperty(XMLInputFactory.IS_VALIDATING, false); 108 109 securityLogger.info("Secure XMLInputFactory created with XXE protection"); 110 return factory; 111 } 112 113 /** 114 * 安全に設定されたTransformerFactoryを作成します 115 * 116 * @return 安全に設定されたTransformerFactory 117 */ 118 public static TransformerFactory createSecureTransformerFactory() { 119 TransformerFactory factory = TransformerFactory.newInstance(); 120 121 try { 122 // XMLTransform攻撃を防ぐための設定 123 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 124 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); 125 } catch (Exception e) { 126 logger.warn("Failed to set external access attributes for TransformerFactory", e); 127 } 128 129 // 機能制限 130 try { 131 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); 132 } catch (Exception e) { 133 logger.warn("Failed to enable secure processing feature", e); 134 } 135 136 securityLogger.info("Secure TransformerFactory created"); 137 return factory; 138 } 139 140 /** 141 * 安全に設定されたSchemaFactoryを作成します 142 * 143 * @return 安全に設定されたSchemaFactory 144 */ 145 public static SchemaFactory createSecureSchemaFactory() { 146 SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 147 148 try { 149 // 外部リソースアクセスを制限 150 factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 151 factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); 152 } catch (Exception e) { 153 logger.warn("Failed to set external access properties for SchemaFactory", e); 154 } 155 156 // セキュアプロセシング機能を有効化 157 try { 158 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); 159 } catch (Exception e) { 160 logger.warn("Failed to enable secure processing feature for SchemaFactory", e); 161 } 162 163 securityLogger.info("Secure SchemaFactory created"); 164 return factory; 165 } 166 167 /** 168 * InputStreamからのXML読み込みを安全に行います 169 * 170 * @param inputStream 読み込み対象のInputStream 171 * @return 安全に解析されたDocumentBuilder 172 * @throws ParserConfigurationException XML設定エラーが発生した場合 173 */ 174 public static DocumentBuilder createSecureDocumentBuilderForStream(InputStream inputStream) 175 throws ParserConfigurationException { 176 177 // 入力検証 178 if (inputStream == null) { 179 throw new IllegalArgumentException("InputStream cannot be null"); 180 } 181 182 DocumentBuilder builder = createSecureDocumentBuilder(); 183 184 // エラーハンドラーの設定(セキュリティ上の理由により詳細エラー情報を制限) 185 builder.setErrorHandler(new SecurityAwareErrorHandler()); 186 187 securityLogger.debug("Secure DocumentBuilder created for InputStream processing"); 188 return builder; 189 } 190} 191 192/** セキュリティを考慮したXMLエラーハンドラー 詳細なエラー情報の漏洩を防ぐため、一般的なエラーメッセージのみを提供 */ 193class SecurityAwareErrorHandler implements org.xml.sax.ErrorHandler { 194 private static final Logger logger = LoggerFactory.getLogger(SecurityAwareErrorHandler.class); 195 private static final Logger securityLogger = 196 LoggerFactory.getLogger("com.streamConverter.security"); 197 198 @Override 199 public void warning(org.xml.sax.SAXParseException exception) { 200 logger.debug("XML parsing warning (details suppressed for security)"); 201 securityLogger.warn("XML parsing warning detected during secure processing"); 202 } 203 204 @Override 205 public void error(org.xml.sax.SAXParseException exception) { 206 logger.debug("XML parsing error (details suppressed for security)"); 207 securityLogger.warn("XML parsing error detected during secure processing"); 208 } 209 210 @Override 211 public void fatalError(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException { 212 securityLogger.error("Fatal XML parsing error detected during secure processing"); 213 throw new org.xml.sax.SAXException("XML processing failed due to security constraints"); 214 } 215}