Wed, 10 Jun 2020 17:52:53 +0200
Code Style Checker: continued to implement checker for security related issues.
# -*- coding: utf-8 -*- # Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a check for SQL injection. """ # # This is a modified version of the one found in the bandit package. # # Original Copyright 2014 Hewlett-Packard Development Company, L.P. # # SPDX-License-Identifier: Apache-2.0 # import ast import re from Security import SecurityUtils def getChecks(): """ Public method to get a dictionary with checks handled by this module. @return dictionary containing checker lists containing checker function and list of codes @rtype dict """ return { "Str": [ (checkHardcodedSqlExpressions, ("S608",)), ], } SIMPLE_SQL_RE = re.compile( r'(select\s.*from\s|' r'delete\s+from\s|' r'insert\s+into\s.*values\s|' r'update\s.*set\s)', re.IGNORECASE | re.DOTALL, ) def _checkString(data): """ Function to check a given string against the list of search patterns. @param data string data to be checked @type str @return flag indicating a match @rtype bool """ return SIMPLE_SQL_RE.search(data) is not None def _evaluateAst(node): """ Function to analyze the given ast node. @param node ast node to be analyzed @type ast.Str @return tuple containing a flag indicating an execute call and the resulting statement @rtype tuple of (bool, str) """ wrapper = None statement = '' if isinstance(node._securityParent, ast.BinOp): out = SecurityUtils.concatString(node, node._securityParent) wrapper = out[0]._securityParent statement = out[1] elif ( isinstance(node._securityParent, ast.Attribute) and node._securityParent.attr == 'format' ): statement = node.s # Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str wrapper = node._securityParent._securityParent._securityParent elif ( hasattr(ast, 'JoinedStr') and isinstance(node._securityParent, ast.JoinedStr) ): statement = node.s wrapper = node._securityParent._securityParent if isinstance(wrapper, ast.Call): # wrapped in "execute" call? names = ['execute', 'executemany'] name = SecurityUtils.getCalledName(wrapper) return (name in names, statement) else: return (False, statement) def checkHardcodedSqlExpressions(reportError, context, config): """ Function to check for SQL injection. @param reportError function to be used to report errors @type func @param context security context object @type SecurityContext @param config dictionary with configuration data @type dict """ val = _evaluateAst(context.node) if _checkString(val[1]): reportError( context.node.lineno - 1, context.node.col_offset, "S608", "M", "M" if val[0] else "L", )