def basic_auth_literal(context):
call_node = context.node
parent = s_utils.get_top_parent_node(call_node)
if not (isinstance(call_node.func, ast.Attribute) and call_node.func.attr == 'add_header'):
return
klass_name = next(
(klass for klass in s_utils.iter_method_classes(parent, call_node, context) if klass in ('urllib2.Request', 'urllib.request.Request')),
None
)
if klass_name is None:
return
if not len(call_node.args) == 2:
return
arg0, arg1 = call_node.args[:2]
if not (isinstance(arg0, ast.Str) and arg0.s.lower() == 'authorization'):
return
if isinstance(arg1, ast.BinOp) and isinstance(arg1.left, ast.Str):
str_node = arg1.left
str_node.parent = arg1
elif isinstance(arg1, ast.Str):
str_node = arg1
else:
return
if re.match(r'^basic\s+', str_node.s, flags=re.IGNORECASE) is None:
return
issue = bandit.Issue(
severity=bandit.HIGH,
confidence=bandit.MEDIUM,
text='A hard-coded string is being used as an HTTP basic authorization header'
)
if re.match(r'^basic\s+[\w]{2,}={0,2}$', str_node.s, flags=re.IGNORECASE):
return issue
if not isinstance(str_node.parent, ast.BinOp):
return
binop_node = str_node.parent
if not (isinstance(binop_node.op, (ast.Add, ast.Mod)) and binop_node.left == str_node):
return
header_value = None
if isinstance(binop_node.right, ast.Call):
call_name = b_utils.get_call_name(binop_node.right, context._context['import_aliases'])
if re.match(r'base64.(standard_|urlsafe_)?b64encode', call_name) is None:
return
header_value = next((value for value in s_utils.get_call_arg_values(parent, binop_node.right, arg=0) if isinstance(value, (str, bytes))), None)
elif isinstance(binop_node.right, (ast.Name, ast.Str)):
header_value = next((value for value in s_utils.iter_expr_literal_values(parent, binop_node.right) if isinstance(value, (str, bytes))), None)
if header_value is None:
return
return issue
评论列表
文章目录