StackOverflowException при вызове XmlElement.OuterXml в глубоко вложенном xml - PullRequest
2 голосов
/ 27 августа 2010

У меня проблема с проверкой некоторых входных XML-данных на моем WebService.Я включаю все, что вам нужно, чтобы воспроизвести ошибку, так что, надеюсь, кто-нибудь сможет мне помочь.Заранее спасибо!

У меня есть хакер, который отправляет мне недопустимый XML-код на мой общедоступный интерфейс, и вместо того, чтобы быть обнаруженным в моей проверке XSD, он завершает работу всего IIS WebApp еще до того, как попадает в XSD,и я не могу обойти его!Вот XML, который он отправляет:

<?xml version="1.0"?>
<Security xmlns="">
    <SecurityPermissions>
        <SecurityPermission ActionID="90" Value="1"></SecurityPermission>
        <SecurityPermission ActionID="80" Value="1"></SecurityPermission>
    </SecurityPermissions>
    <C><C><C><C><C>...</C></C></C></C></C>
</Security>

Недопустимая вещь - это вложенные узлы.Я сократил XML здесь, но они похожи на 1000 уровней глубиной.

Для полного XML, пожалуйста, скачайте его ЗДЕСЬ .

Для файла XSD, пожалуйста, скачайте его ЗДЕСЬ .

Вот схема XSD:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema targetNamespace="UpdatePermissions.xsd" xmlns="UpdatePermissions.xsd" xmlns:mstns="UpdatePermissions.xsd" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" >
    <xs:element name="Security">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="SecurityPermissions" minOccurs="1" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="SecurityPermission" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="ActionID" type="xs:int" use="required" />
                                    <xs:attribute name="Value" type="xs:int" use="required" />
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

ВАЖНАЯ ТОЧКА:

Поскольку вход XML имеет xmlns = "" (и именно так его передают ВСЕ мои клиенты), я вынужден изменить введенный XML с новым значением xmlns (я установил его в xmlns =«UpdatePermissions.xsd»), чтобы проверка XSD работала.Поскольку вы не можете просто установить xmlns в существующем элементе XmlElement, я должен скопировать XML в XmlDocumentFragment.Это - наряду с вложенными узлами - приводит к сбою моего приложения с StackOverflowException, который не может быть пойман в try..catch.Вот как это выглядит:

    [WebMethod]
    public XmlElement UpdatePermissions(XmlElement xInput)
    {
        var errors = ValidateUpdatePermissionsXml(xInput);

        if (errors.Count > 0)
            throw new Exception(" I hate everything");

        // do other processing

        return xInput;
    }


    public List<string> ValidateUpdatePermissionsXml(XmlElement xInput)
    {
        // set xmlns since it isn't provided by caller but we need it to validate against XSD
        xInput.SetAttribute("xmlns", "UpdatePermissions.xsd");

        // transfer XML to a fragment otherwise xmlns attribute we set wouldn't take effect
        var fragment = xInput.OwnerDocument.CreateDocumentFragment();
        var xmlString = xInput.OuterXml; //  <---- THIS IS WHERE THE APP CRASHES
        fragment.InnerXml = xmlString;

        //setup errors array
        var errors = new List<string>();

        //read in schema
        var schemaStream = File.OpenRead(@"c:\UpdatePermissions.xsd");
        var schema = XmlSchema.Read(schemaStream, null);
        var schemaSet = new XmlSchemaSet();
        schemaSet.Add(schema);

        //setup validation settings
        var readerSettings = new XmlReaderSettings();
        readerSettings.ValidationType = ValidationType.Schema;
        readerSettings.Schemas = schemaSet;
        readerSettings.ValidationEventHandler += (s, e) => errors.Add(e.Exception.Message);

        //create readers
        var nodeReader = new XmlNodeReader(fragment);
        var reader = XmlReader.Create(nodeReader, readerSettings);

        //read
        while (reader.Read()) ;

        return errors;
    }

Вот мой модульный тест, который всегда терпит неудачу:

    [TestMethod]
    public void TestXSDValidation_Invalid_DeeplyNestedNodes()
    {
        //load Xml from file into XmlElement
        var badXml = File.ReadAllText(@"c:\UpdatePermissions_BadRequest.xml");
        var doc = new XmlDocument();
        doc.LoadXml(badXml);
        var badElement = doc.DocumentElement;

        var errors = ValidateUpdatePermissionsXml(badElement);

        Assert.AreEqual(1, errors.Count);
        Assert.AreEqual("The element 'SecurityPermissions' in namespace 'UpdatePermissions.xsd' has invalid child element 'C' in namespace 'UpdatePermissions.xsd'. List of possible elements expected: 'SecurityPermission' in namespace 'UpdatePermissions.xsd'.", errors[0]);
    }

Похоже, что вызов .OuterXml завершается неудачей с StackOverflowException из-за того, насколько глубокоузлы являются вложенными.Все мои попытки записать XML в строку другими способами также потерпели неудачу.

Проблема

Что я не могу понять, так это то, как я могу принять XML, который имеетУДАЛИТЬ значение атрибута xmlns, и все равно выполнять проверку, не копируя XML-файл во фрагмент.Все, что я пробовал, что каким-то образом записывает XML, терпит неудачу и вылетает из приложения.Попробуйте, и вы поймете, о чем я!

1 Ответ

0 голосов
/ 26 января 2011

Вместо того, чтобы пытаться преобразовать весь запрос в строку, почему бы не проанализировать xml с помощью XmlTextReader потока запросов?Здесь есть статья, предоставляющая более подробную информацию об этом классе:

http://support.microsoft.com/kb/307548

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...