diff options
author | Christian Heimes <christian@cheimes.de> | 2013-02-15 01:16:54 +0100 |
---|---|---|
committer | Christian Heimes <christian@cheimes.de> | 2013-02-15 01:16:54 +0100 |
commit | baf18e812a631209cb2a72fd30e2f70414a3c9a2 (patch) | |
tree | 857ee6b51fd1637dad5f833cd7b39a9fb01578b5 | |
parent | eccaa9892919446510e995ad83776c39ed8184d0 (diff) | |
download | defusedxml-baf18e812a631209cb2a72fd30e2f70414a3c9a2.tar.gz |
xmlrpclib's ExpatParser needs protection, too
-rw-r--r-- | CHANGES.txt | 11 | ||||
-rw-r--r-- | README.txt | 33 | ||||
-rw-r--r-- | tests.py | 60 |
3 files changed, 78 insertions, 26 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index e8d90d7..6bb87cb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,11 +6,14 @@ defusedxml 0.2 *Release date: ??-Feb-2013* -- Renamed ExternalEntitiesForbidden to ExternalReferenceForbidden -- Renamed defusedxml.lxml.check_dtd() to check_docinfo() -- Unified argument names in callbacks -- Added arguments and formatted representation to exceptions +- Rename ExternalEntitiesForbidden to ExternalReferenceForbidden +- Rename defusedxml.lxml.check_dtd() to check_docinfo() +- Unify argument names in callbacks +- Add arguments and formatted representation to exceptions +- Add forbid_external argument to all functions and classs - More tests +- LOTS of documentation +- Add example code for other languages (Ruby, Perl, PHP) and parsers (Genshi) defusedxml 0.1 -------------- @@ -176,19 +176,20 @@ Python XML Libraries ==================== .. csv-table:: - :header: "kind", "sax", "etree", "minidom", "pulldom", "lxml", "genshi" - :widths: 24, 8, 8, 8, 8, 8, 8 - - "billion laughs", "True", "True", "True", "True", "False (1)", "False (5)" - "quadratic blowup", "True", "True", "True", "True", "True", "False (5)" - "external entity expansion (remote)", "True", "False (3)", "False (4)", "True", "False (1)", "False (5)" - "external entity expansion (local file)", "True", "False (3)", "False (4)", "True", "True", "False (5)" - "DTD retrieval", "True", "False", "False", "True", "False (1)", "False" - "gzip bomb", "False", "False", "False", "False", "partly (2)", "False" - "xpath support", "False", "False", "False", "False", "True", "False" - "xsl(t) support", "False", "False", "False", "False", "True", "False" - "xinclude support", "False", "True (6)", "False", "False", "True (6)", "True" - "C library", "expat", "expat", "expat", "expat", "libxml2", "expat" + :header: "kind", "sax", "etree", "minidom", "pulldom", "xmlrpc", "lxml", "genshi" + :widths: 24, 7, 8, 8, 7, 8, 8, 8 + :stub-columns: 0 + + "billion laughs", "**True**", "**True**", "**True**", "**True**", "**True**", "False (1)", "False (5)" + "quadratic blowup", "**True**", "**True**", "**True**", "**True**", "**True**", "**True**", "False (5)" + "external entity expansion (remote)", "**True**", "False (3)", "False (4)", "**True**", "untested", "False (1)", "False (5)" + "external entity expansion (local file)", "**True**", "False (3)", "False (4)", "**True**", "untested", "**True**", "False (5)" + "DTD retrieval", "**True**", "False", "False", "**True**", "untested", "False (1)", "False" + "gzip bomb", "False", "False", "False", "False", "**True**", "**partly** (2)", "False" + "xpath support", "False", "False", "False", "False", "False", "**True**", "False" + "xsl(t) support", "False", "False", "False", "False", "False", "**True**", "False" + "xinclude support", "False", "**True** (6)", "False", "False", "False", "**True** (6)", "**True**" + "C library", "expat", "expat", "expat", "expat", "expat", "libxml2", "expat" 1. Lxml is protected against billion laughs attacks and doesn't do network lookups by default. @@ -275,6 +276,11 @@ defused.pulldom parse(), parseString() +defused.xmlrpclib +----------------- + +TODO + defused.lxml ------------ @@ -506,6 +512,7 @@ TODO * SAX: take feature_external_ges and feature_external_pes (?) into account * implement monkey patching of stdlib modules * document which module / library is vulnerable to which kind of attack +* Add fix for xmlrpc's ExpatParser * documentation, documentation, documentation ... @@ -14,6 +14,10 @@ from defusedxml import (DefusedXmlException, DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden, NotSupportedError) from defusedxml.common import PY3, PY26, PY31 +if PY3: + from xmlrpclib.client import ExpatParser as XmlRpcParser +else: + from xmlrpclib import ExpatParser as XmlRpcParser try: from defusedxml import lxml @@ -67,19 +71,13 @@ if PY26 or PY31: return True -class BaseTests(unittest.TestCase): - module = None +class DefusedTestCase(unittest.TestCase): if PY3: content_binary = False else: content_binary = True - dtd_external_ref = False - - external_ref_exception = ExternalReferenceForbidden - cyclic_error = None - xml_dtd = os.path.join(HERE, "xmltestdata", "dtd.xml") xml_external = os.path.join(HERE, "xmltestdata", "external.xml") xml_external_file = os.path.join(HERE, "xmltestdata", "external_file.xml") @@ -111,6 +109,15 @@ class BaseTests(unittest.TestCase): data = f.read() return data + +class BaseTests(DefusedTestCase): + module = None + dtd_external_ref = False + + external_ref_exception = ExternalReferenceForbidden + cyclic_error = None + + def test_simple_parse(self): self.parse(self.xml_simple) self.parseString(self.get_content(self.xml_simple)) @@ -193,8 +200,8 @@ class TestDefusedElementTree(BaseTests): module = ElementTree - # etree doesn't do external ref lookup - external_ref_exception = ElementTree.ParseError + ## etree doesn't do external ref lookup + #external_ref_exception = ElementTree.ParseError cyclic_error = ElementTree.ParseError @@ -391,6 +398,40 @@ class TestDefusedLxml(BaseTests): self.assertEqual(elements, list(root)[:1]) +class XmlRpcTarget(object): + def __init__(self): + self._data = [] + + def __str__(self): + return "\n".join(self._data) + + def xml(self, encoding, standalone): + pass + + def start(self, tag, attrs): + self._data.append("<%s>" % tag) + + def data(self, text): + self._data.append(text) + + def end(self, tag): + self._data.append("</%s>" % tag) + + +class TestXmlRpc(DefusedTestCase): + def parse(self, xmlfile): + target = XmlRpcTarget() + parser = XmlRpcParser(target) + data = self.get_content(xmlfile) + parser.feed(data) + parser.close() + return target + + def test_xmlrpc(self): + self.parse(self.xml_bomb) + self.parse(self.xml_quadratic) + + def test_main(): suite = unittest.TestSuite() suite.addTests(unittest.makeSuite(TestDefusedcElementTree)) @@ -398,6 +439,7 @@ def test_main(): suite.addTests(unittest.makeSuite(TestDefusedMinidom)) suite.addTests(unittest.makeSuite(TestDefusedPulldom)) suite.addTests(unittest.makeSuite(TestDefusedSax)) + suite.addTests(unittest.makeSuite(TestXmlRpc)) if lxml is not None: suite.addTests(unittest.makeSuite(TestDefusedLxml)) return suite |