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:
parent
45ff8d345f
commit
4b03e062f1
|
@ -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']
|
||||
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
19
setup.cfg
19
setup.cfg
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue