
Currently the check_example in test_functional computes sums and on error tells the developer the difference in sums, which is confusing and error prone. It also leads to false positives where sums may be correct, but the exact number of MEDIUM, HIGH, etc is different. This was the case for two tests: test_xml and test_secret_config_option. The general_hardcoded_password test was also broken for py35 because it was assuming function args are ast.Name not ast.arg. But surprisingly the tests passed because of a syntax error in the example. Change-Id: Icd06fb7ca27a8a01d6442f199775d474d436371b
216 lines
6.2 KiB
Python
216 lines
6.2 KiB
Python
# -*- coding:utf-8 -*-
|
|
#
|
|
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# 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.
|
|
|
|
import ast
|
|
import sys
|
|
|
|
import bandit
|
|
from bandit.core import test_properties as test
|
|
|
|
|
|
CANDIDATES = set(["password", "pass", "passwd", "pwd", "secret", "token",
|
|
"secrete"])
|
|
|
|
|
|
def _report(value):
|
|
return bandit.Issue(
|
|
severity=bandit.LOW,
|
|
confidence=bandit.MEDIUM,
|
|
text=("Possible hardcoded password: '%s'" % value))
|
|
|
|
|
|
@test.checks('Str')
|
|
@test.test_id('B105')
|
|
def hardcoded_password_string(context):
|
|
"""**B105: Test for use of hard-coded password strings**
|
|
|
|
The use of hard-coded passwords increases the possibility of password
|
|
guessing tremendously. This plugin test looks for all string literals and
|
|
checks the following conditions:
|
|
|
|
- assigned to a variable that looks like a password
|
|
- assigned to a dict key that looks like a password
|
|
- used in a comparison with a variable that looks like a password
|
|
|
|
Variables are considered to look like a password if they have match any one
|
|
of:
|
|
|
|
- "password"
|
|
- "pass"
|
|
- "passwd"
|
|
- "pwd"
|
|
- "secret"
|
|
- "token"
|
|
- "secrete"
|
|
|
|
Note: this can be noisy and may generate false positives.
|
|
|
|
**Config Options:**
|
|
|
|
None
|
|
|
|
:Example:
|
|
|
|
.. code-block:: none
|
|
|
|
>> Issue: Possible hardcoded password '(root)'
|
|
Severity: Low Confidence: Low
|
|
Location: ./examples/hardcoded-passwords.py:5
|
|
4 def someFunction2(password):
|
|
5 if password == "root":
|
|
6 print("OK, logged in")
|
|
|
|
.. seealso::
|
|
|
|
- https://www.owasp.org/index.php/Use_of_hard-coded_password
|
|
|
|
.. versionadded:: 0.9.0
|
|
|
|
"""
|
|
node = context.node
|
|
if isinstance(node.parent, ast.Assign):
|
|
# looks for "candidate='some_string'"
|
|
for targ in node.parent.targets:
|
|
if isinstance(targ, ast.Name) and targ.id in CANDIDATES:
|
|
return _report(node.s)
|
|
|
|
elif isinstance(node.parent, ast.Index) and node.s in CANDIDATES:
|
|
# looks for "dict[candidate]='some_string'"
|
|
# assign -> subscript -> index -> string
|
|
assign = node.parent.parent.parent
|
|
if isinstance(assign, ast.Assign) and isinstance(assign.value,
|
|
ast.Str):
|
|
return _report(assign.value.s)
|
|
|
|
elif isinstance(node.parent, ast.Compare):
|
|
# looks for "candidate == 'some_string'"
|
|
comp = node.parent
|
|
if isinstance(comp.left, ast.Name) and comp.left.id in CANDIDATES:
|
|
if isinstance(comp.comparators[0], ast.Str):
|
|
return _report(comp.comparators[0].s)
|
|
|
|
|
|
@test.checks('Call')
|
|
@test.test_id('B106')
|
|
def hardcoded_password_funcarg(context):
|
|
"""**B106: Test for use of hard-coded password function arguments**
|
|
|
|
The use of hard-coded passwords increases the possibility of password
|
|
guessing tremendously. This plugin test looks for all function calls being
|
|
passed a keyword argument that is a string literal. It checks that the
|
|
assigned local variable does not look like a password.
|
|
|
|
Variables are considered to look like a password if they have match any one
|
|
of:
|
|
|
|
- "password"
|
|
- "pass"
|
|
- "passwd"
|
|
- "pwd"
|
|
- "secret"
|
|
- "token"
|
|
- "secrete"
|
|
|
|
Note: this can be noisy and may generate false positives.
|
|
|
|
**Config Options:**
|
|
|
|
None
|
|
|
|
:Example:
|
|
|
|
.. code-block:: none
|
|
|
|
>> Issue: [B106:hardcoded_password_funcarg] Possible hardcoded
|
|
password: 'blerg'
|
|
Severity: Low Confidence: Medium
|
|
Location: ./examples/hardcoded-passwords.py:16
|
|
15
|
|
16 doLogin(password="blerg")
|
|
|
|
.. seealso::
|
|
|
|
- https://www.owasp.org/index.php/Use_of_hard-coded_password
|
|
|
|
.. versionadded:: 0.9.0
|
|
|
|
"""
|
|
# looks for "function(candidate='some_string')"
|
|
for kw in context.node.keywords:
|
|
if isinstance(kw.value, ast.Str) and kw.arg in CANDIDATES:
|
|
return _report(kw.value.s)
|
|
|
|
|
|
@test.checks('FunctionDef')
|
|
@test.test_id('B107')
|
|
def hardcoded_password_default(context):
|
|
"""**B107: Test for use of hard-coded password argument defaults**
|
|
|
|
The use of hard-coded passwords increases the possibility of password
|
|
guessing tremendously. This plugin test looks for all function definitions
|
|
that specify a default string literal for some argument. It checks that
|
|
the argument does not look like a password.
|
|
|
|
Variables are considered to look like a password if they have match any one
|
|
of:
|
|
|
|
- "password"
|
|
- "pass"
|
|
- "passwd"
|
|
- "pwd"
|
|
- "secret"
|
|
- "token"
|
|
- "secrete"
|
|
|
|
Note: this can be noisy and may generate false positives.
|
|
|
|
**Config Options:**
|
|
|
|
None
|
|
|
|
:Example:
|
|
|
|
.. code-block:: none
|
|
|
|
>> Issue: [B107:hardcoded_password_default] Possible hardcoded
|
|
password: 'Admin'
|
|
Severity: Low Confidence: Medium
|
|
Location: ./examples/hardcoded-passwords.py:1
|
|
|
|
1 def someFunction(user, password="Admin"):
|
|
2 print("Hi " + user)
|
|
|
|
.. seealso::
|
|
|
|
- https://www.owasp.org/index.php/Use_of_hard-coded_password
|
|
|
|
.. versionadded:: 0.9.0
|
|
|
|
"""
|
|
# looks for "def function(candidate='some_string')"
|
|
|
|
# this pads the list of default values with "None" if nothing is given
|
|
defs = [None] * (len(context.node.args.args) -
|
|
len(context.node.args.defaults))
|
|
defs.extend(context.node.args.defaults)
|
|
|
|
# go through all (param, value)s and look for candidates
|
|
for key, val in zip(context.node.args.args, defs):
|
|
if isinstance(key, ast.Name) or isinstance(key, ast.arg):
|
|
check = key.arg if sys.version_info.major > 2 else key.id # Py3
|
|
if isinstance(val, ast.Str) and check in CANDIDATES:
|
|
return _report(val.s)
|