All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.kernel.utils;

import com.itextpdf.commons.utils.MessageFormatUtil;
import com.itextpdf.io.util.XmlUtil;
import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
import com.itextpdf.kernel.exceptions.PdfException;
import com.itextpdf.kernel.logs.KernelLogMessageConstant;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;

/**
 * Implementation of {@link IXmlParserFactory} for creating safe xml parser objects.
 * Creates parsers with configuration to prevent XML bombs and XXE attacks.
 */
public class DefaultSafeXmlParserFactory implements IXmlParserFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSafeXmlParserFactory.class);

    /**
     * Feature for disallowing DOCTYPE declaration.
     *
     * 

* Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl */ private final static String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl"; /** * If you can't disable DOCTYPE declarations, then at least disable external entities. * Must be used with the {@link DefaultSafeXmlParserFactory#EXTERNAL_PARAMETER_ENTITIES}, otherwise has no effect. * *

* Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities * Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities * JDK7+ - http://xml.org/sax/features/external-general-entities */ private final static String EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities"; /** * Must be used with the {@link DefaultSafeXmlParserFactory#EXTERNAL_GENERAL_ENTITIES}, otherwise has no effect. * *

* Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities * Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities * JDK7+ - http://xml.org/sax/features/external-parameter-entities */ private final static String EXTERNAL_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities"; /** * Disable external DTDs. */ private final static String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; /** * Creates instance of {@link DefaultSafeXmlParserFactory}. */ public DefaultSafeXmlParserFactory() { // empty constructor } @Override public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) { DocumentBuilderFactory factory = createDocumentBuilderFactory(); configureSafeDocumentBuilderFactory(factory); factory.setNamespaceAware(namespaceAware); factory.setIgnoringComments(ignoringComments); DocumentBuilder db; try { db = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new PdfException(e.getMessage(), e); } db.setEntityResolver(new SafeEmptyEntityResolver()); return db; } @Override public XMLReader createXMLReaderInstance(boolean namespaceAware, boolean validating) { SAXParserFactory factory = createSAXParserFactory(); factory.setNamespaceAware(namespaceAware); factory.setValidating(validating); configureSafeSAXParserFactory(factory); XMLReader xmlReader; try { SAXParser saxParser = factory.newSAXParser(); xmlReader = saxParser.getXMLReader(); } catch (ParserConfigurationException | SAXException e) { throw new PdfException(e.getMessage(), e); } xmlReader.setEntityResolver(new SafeEmptyEntityResolver()); return xmlReader; } @Override public Transformer createTransformerInstance() { TransformerFactory factory = TransformerFactory.newInstance(); configureSafeTransformerFactory(factory); Transformer transformer; try { transformer = factory.newTransformer(); } catch (TransformerConfigurationException e) { throw new PdfException(e.getMessage(), e); } return transformer; } /** * Creates a document builder factory implementation. * * @return result of {@link DocumentBuilderFactory#newInstance()} call */ protected DocumentBuilderFactory createDocumentBuilderFactory() { return XmlUtil.getDocumentBuilderFactory(); } /** * Creates a SAX parser factory implementation. * * @return result of {@link SAXParserFactory#newInstance()} call */ protected SAXParserFactory createSAXParserFactory() { return XmlUtil.createSAXParserFactory(); } /** * Configures document builder factory to make it secure against xml attacks. * * @param factory {@link DocumentBuilderFactory} instance to be configured */ protected void configureSafeDocumentBuilderFactory(DocumentBuilderFactory factory) { tryToSetFeature(factory, DISALLOW_DOCTYPE_DECL, true); tryToSetFeature(factory, EXTERNAL_GENERAL_ENTITIES, false); tryToSetFeature(factory, EXTERNAL_PARAMETER_ENTITIES, false); tryToSetFeature(factory, LOAD_EXTERNAL_DTD, false); // recommendations from Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" factory.setXIncludeAware(false); factory.setExpandEntityReferences(false); } /** * Configures SAX parser factory to make it secure against xml attacks. * * @param factory {@link SAXParserFactory} instance to be configured */ protected void configureSafeSAXParserFactory(SAXParserFactory factory) { tryToSetFeature(factory, DISALLOW_DOCTYPE_DECL, true); tryToSetFeature(factory, EXTERNAL_GENERAL_ENTITIES, false); tryToSetFeature(factory, EXTERNAL_PARAMETER_ENTITIES, false); tryToSetFeature(factory, LOAD_EXTERNAL_DTD, false); // recommendations from Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" factory.setXIncludeAware(false); } /** * Configures transformer factory to make it secure against xml attacks. * * @param factory {@link TransformerFactory} instance to be configured */ protected void configureSafeTransformerFactory(TransformerFactory factory) { } private void tryToSetFeature(DocumentBuilderFactory factory, String feature, boolean value) { try { factory.setFeature(feature, value); } catch (ParserConfigurationException e) { LOGGER.info(MessageFormatUtil .format(KernelLogMessageConstant.FEATURE_IS_NOT_SUPPORTED, e.getMessage(), feature)); } } private void tryToSetFeature(SAXParserFactory factory, String feature, boolean value) { try { factory.setFeature(feature, value); } catch (ParserConfigurationException | SAXNotRecognizedException | SAXNotSupportedException e) { LOGGER.info(MessageFormatUtil .format(KernelLogMessageConstant.FEATURE_IS_NOT_SUPPORTED, e.getMessage(), feature)); } } // Prevents XXE attacks private static class SafeEmptyEntityResolver implements EntityResolver { public SafeEmptyEntityResolver() { // empty constructor } public InputSource resolveEntity(String publicId, String systemId) { throw new PdfException(KernelExceptionMessageConstant.EXTERNAL_ENTITY_ELEMENT_FOUND_IN_XML); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy