--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py Wed Jun 10 17:52:53 2020 +0200 @@ -0,0 +1,118 @@ +# -*- 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", + )