Revised XML tests

The XML test plugins were all checking for a specific function call
or a specific module import. This functionality exists in a generic
form via blacklist_imports and blacklist_calls. This changes removes
the specific XML tests and replaces the functionality using these
blacklist checks.

Closes-bug: 1477542
Change-Id: I7bcd5a9c2d9343e6306285afca59012579ab0a9a
This commit is contained in:
Tim Kelsey 2015-07-24 14:26:10 +01:00
parent 45ff8d345f
commit 4b03e062f1
4 changed files with 69 additions and 299 deletions

View File

@ -82,6 +82,51 @@ blacklist_calls:
message: "Standard pseudo-random generators are not suitable for security/cryptographic purposes."
level: "LOW"
# Most of this is based off of Christian Heimes' work on defusedxml:
# https://pypi.python.org/pypi/defusedxml/#defusedxml-sax
- xml_bad_cElementTree:
qualnames: [xml.etree.cElementTree.parse,
xml.etree.cElementTree.iterparse,
xml.etree.cElementTree.fromstring,
xml.etree.cElementTree.XMLParser]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_ElementTree:
qualnames: [xml.etree.ElementTree.parse,
xml.etree.ElementTree.iterparse,
xml.etree.ElementTree.fromstring,
xml.etree.ElementTree.XMLParser]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_expatreader:
qualnames: [xml.sax.expatreader.create_parser]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_expatbuilder:
qualnames: [xml.dom.expatbuilder.parse,
xml.dom.expatbuilder.parseString]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_sax:
qualnames: [xml.sax.parse,
xml.sax.parseString,
xml.sax.make_parser]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_minidom:
qualnames: [xml.dom.minidom.parse,
xml.dom.minidom.parseString]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_pulldom:
qualnames: [xml.dom.pulldom.parse,
xml.dom.pulldom.parseString]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
- xml_bad_etree:
qualnames: [lxml.etree.parse,
lxml.etree.fromstring,
lxml.etree.RestrictedElement,
lxml.etree.GlobalParserTLS,
lxml.etree.getDefaultParser,
lxml.etree.check_docinfo]
message: "Using {func} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {func} with it's defusedxml equivilent function."
shell_injection:
# Start a process using the subprocess module, or one of its wrappers.
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call,
@ -107,6 +152,26 @@ blacklist_imports:
level: LOW
message: "Consider possible security implications associated with {module} module."
# Most of this is based off of Christian Heimes' work on defusedxml:
# https://pypi.python.org/pypi/defusedxml/#defusedxml-sax
- xml_libs:
imports: [xml.etree.cElementTree,
xml.etree.ElementTree,
xml.sax.expatreader,
xml.sax,
xml.dom.expatbuilder,
xml.dom.minidom,
xml.dom.pulldom,
lxml.etree,
lxml]
message: "Using {module} to parse untrusted XML data is known to be vulnerable to XML attacks. Replace {module} with the equivilent defusedxml package."
level: LOW
- xml_libs_high:
imports: [xmlrpclib]
message: "Using {module} to parse untrusted XML data is known to be vulnerable to XML attacks. Use defused.xmlrpc.monkey_patch() function to monkey-patch xmlrpclib and mitigate XML vulnerabilities."
level: HIGH
hardcoded_tmp_directory:
tmp_dirs: ['/tmp', '/var/tmp', '/dev/shm']

View File

@ -76,9 +76,12 @@ def blacklist_calls(context, config):
elif check[3] == 'LOW':
level = bandit.LOW
message = check[2].replace("{func}",
context.call_function_name_qual)
return bandit.Issue(
severity=level, confidence=confidence,
text="%s %s" % (check[2], context.call_args_string)
text="%s %s" % (message, context.call_args_string)
)

View File

@ -1,279 +0,0 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Most of this file is based off of Christian Heimes' work on defusedxml:
# https://pypi.python.org/pypi/defusedxml/#defusedxml-sax
import bandit
from bandit.core.test_properties import *
###############################################################################
# check function calls
###############################################################################
@checks('Call')
def etree_celement_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'iterparse', 'fromstring', 'XMLParser']
if 'xml.etree.cElementTree' == qual and func in blacklist:
s = ("Using xml.etree.cElementTree.%s to parse untrusted XML data"
" is known to be vulnerable to XML attacks. Replace "
" xml.etree.cElementTree.%s with defusedxml.cElementTree.%s"
" function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def etree_element_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'iterparse', 'fromstring', 'XMLParser']
if 'xml.etree.ElementTree' == qual and func in blacklist:
s = ("Using xml.etree.ElementTree.%s to parse untrusted XML data"
" is known to be vulnerable to XML attacks. Replace"
" xml.etree.ElementTree.%s with defusedxml.ElementTree.%s"
" function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def expatreader_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['create_parser']
if 'xml.sax.expatreader' == qual and func in blacklist:
s = ("Using xml.sax.expatreader.%s to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" xml.sax.expatreader.%s with defusedxml.expatreader.%s"
" function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def expatbuilder_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'parseString']
if 'xml.dom.expatbuilder' == qual and func in blacklist:
s = ("Using xml.dom.expatbuilder.%s to parse untrusted XML data"
" is known to be vulnerable to XML attacks. Replace"
" xml.dom.expatbuilder.%s with defusedxml.expatbuilder.%s"
" function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def sax_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'parseString', 'make_parser']
if 'xml.sax' == qual and func in blacklist:
s = ("Using xml.sax.%s to parse untrusted XML data is known to"
" be vulnerable to XML attacks. Replace xml.sax.%s with"
" defusedxml.sax.%s function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def minidom_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'parseString']
if 'xml.dom.minidom' == qual and func in blacklist:
s = ("Using xml.dom.minidom.%s to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" xml.dom.minidom.%s with defusedxml.minidom.%s"
" function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def pulldom_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'parseString']
if 'xml.dom.pulldom' == qual and func in blacklist:
s = ("Using xml.dom.pulldom.%s to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" xml.dom.pulldom.%s with defusedxml.pulldom.%s function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
@checks('Call')
def lxml_function_calls(context):
if type(context.call_function_name_qual) == str:
qlist = context.call_function_name_qual.split('.')
qual = '.'.join(qlist[:-1])
func = qlist[-1]
blacklist = ['parse', 'fromstring', 'RestrictedElement',
'GlobalParserTLS', 'getDefaultParser', 'check_docinfo']
if 'lxml.etree' == qual and func in blacklist:
s = ("Using lxml.etree.%s to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" lxml.etree.%s with defused.lxml.%s function.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text=s % (func, func, func))
###############################################################################
# check imports
###############################################################################
@checks('Import', 'ImportFrom')
def etree_celement_import(context):
if context.is_module_being_imported('xml.etree.cElementTree'):
s = ("Using xml.etree.cElementTree to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" xml.etree.cElementTree with defusedxml.cElementTree package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def etree_element_import(context):
if context.is_module_being_imported('xml.etree.ElementTree'):
s = ("Using xml.etree.ElementTree to parse untrusted XML data is"
" known to be vulnerable to XML attacks. Replace"
" xml.etree.ElementTree with defusedxml.ElementTree package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def expatreader_import(context):
if context.is_module_being_imported('xml.sax.expatreader'):
s = ("Using xml.sax.expatreader to parse untrusted XML data is known"
" to be vulnerable to XML attacks. Replace xml.sax.expatreader"
" with defusedxml.expatreader package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def sax_import(context):
if context.is_module_being_imported('xml.sax'):
s = ("Using xml.sax to parse untrusted XML data is known to be"
" vulnerable to XML attacks. Replace xml.sax with defusedxml.sax"
" package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def expatbuilder_import(context):
if context.is_module_being_imported('xml.dom.expatbuilder'):
s = ("Using xml.dom.expatbuilder to parse untrusted XML data is known"
" to be vulnerable to XML attacks. Replace xml.dom.expatbuilder"
" with defusedxml.expatbuilder package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def minidom_import(context):
if context.is_module_being_imported('xml.dom.minidom'):
s = ("Using xml.dom.minidom to parse untrusted XML data is known to be"
" vulnerable to XML attacks. Replace xml.dom.minidom with"
" defusedxml.minidom package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def pulldom_import(context):
if context.is_module_being_imported('xml.dom.pulldom'):
s = ("Using xml.dom.pulldom to parse untrusted XML data is known to be"
" vulnerable to XML attacks. Replace xml.dom.pulldom with"
" defusedxml.pulldom package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)
# this one is 'HIGH' instead of 'LOW' because we know the entire package has
# to be monkeypatched via defusedxml.xmlrpc.monkey_patch()
@checks('Import', 'ImportFrom')
def xmlrpclib_import(context):
if context.is_module_being_imported('xmlrpclib'):
s = ("Using xmlrpclib to parse untrusted XML data is known to be"
" vulnerable to XML attacks. Use defused.xmlrpc.monkey_patch()"
" function to monkey-patch xmlrpclib and mitigate XML"
" vulnerabilities.")
return bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.HIGH,
text=s)
@checks('Import', 'ImportFrom')
def lxml_import(context):
if(context.is_module_being_imported('lxml.etree') or
context.is_module_being_imported('lxml')):
s = ("Using lxml.etree to parse untrusted XML data is known to be"
" vulnerable to XML attacks. Replace lxml.etree with"
" defused.lxml package.")
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
text=s)

View File

@ -94,25 +94,6 @@ bandit.plugins =
# bandit/plugins/try_except_pass.py
try_except_pass = bandit.plugins.try_except_pass:try_except_pass
# bandit/plugins/xlm.py
etree_celement_function_calls = bandit.plugins.xml:etree_celement_function_calls
etree_element_function_calls = bandit.plugins.xml:etree_element_function_calls
expatreader_function_calls = bandit.plugins.xml:expatreader_function_calls
expatbuilder_function_calls = bandit.plugins.xml:expatbuilder_function_calls
sax_function_calls = bandit.plugins.xml:sax_function_calls
minidom_function_calls = bandit.plugins.xml:minidom_function_calls
pulldom_function_calls = bandit.plugins.xml:pulldom_function_calls
lxml_function_calls = bandit.plugins.xml:lxml_function_calls
etree_celement_import = bandit.plugins.xml:etree_celement_import
etree_element_import = bandit.plugins.xml:etree_element_import
expatreader_import = bandit.plugins.xml:expatreader_import
expatbuilder_import = bandit.plugins.xml:expatbuilder_import
sax_import = bandit.plugins.xml:sax_import
minidom_import = bandit.plugins.xml:minidom_import
pulldom_import = bandit.plugins.xml:pulldom_import
xmlrpclib_import = bandit.plugins.xml:xmlrpclib_import
lxml_import = bandit.plugins.xml:lxml_import
[files]
package_data =
bandit = config/bandit.yaml