61 """ |
61 """ |
62 Function to analyze the given ast node. |
62 Function to analyze the given ast node. |
63 |
63 |
64 @param node ast node to be analyzed |
64 @param node ast node to be analyzed |
65 @type ast.Constant |
65 @type ast.Constant |
66 @return tuple containing a flag indicating an execute call and |
66 @return tuple containing a flag indicating an execute call, the resulting |
67 the resulting statement |
67 statement and a flag indicating a string replace call |
68 @rtype tuple of (bool, str) |
68 @rtype tuple of (bool, str, bool) |
69 """ |
69 """ |
70 wrapper = None |
70 wrapper = None |
71 statement = "" |
71 statement = "" |
|
72 strReplace = False |
72 |
73 |
73 if isinstance(node._securityParent, ast.BinOp): |
74 if isinstance(node._securityParent, ast.BinOp): |
74 out = SecurityUtils.concatString(node, node._securityParent) |
75 out = SecurityUtils.concatString(node, node._securityParent) |
75 wrapper = out[0]._securityParent |
76 wrapper = out[0]._securityParent |
76 statement = out[1] |
77 statement = out[1] |
77 elif ( |
78 elif isinstance( |
78 isinstance(node._securityParent, ast.Attribute) |
79 node._securityParent, ast.Attribute |
79 and node._securityParent.attr == "format" |
80 ) and node._securityParent.attr in ("format", "replace"): |
80 ): |
|
81 statement = node.value |
81 statement = node.value |
82 # Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str |
82 # Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str |
83 wrapper = node._securityParent._securityParent._securityParent |
83 wrapper = node._securityParent._securityParent._securityParent |
|
84 if node._securityParent.attr == "replace": |
|
85 strReplace = True |
84 elif hasattr(ast, "JoinedStr") and isinstance(node._securityParent, ast.JoinedStr): |
86 elif hasattr(ast, "JoinedStr") and isinstance(node._securityParent, ast.JoinedStr): |
85 substrings = [ |
87 substrings = [ |
86 child |
88 child |
87 for child in node._securityParent.values |
89 for child in node._securityParent.values |
88 if isinstance(child, ast.Constant) and isinstance(node.value, str) |
90 if isinstance(child, ast.Constant) and isinstance(node.value, str) |
96 wrapper = node._securityParent._securityParent |
98 wrapper = node._securityParent._securityParent |
97 |
99 |
98 if isinstance(wrapper, ast.Call): # wrapped in "execute" call? |
100 if isinstance(wrapper, ast.Call): # wrapped in "execute" call? |
99 names = ["execute", "executemany"] |
101 names = ["execute", "executemany"] |
100 name = SecurityUtils.getCalledName(wrapper) |
102 name = SecurityUtils.getCalledName(wrapper) |
101 return (name in names, statement) |
103 return (name in names, statement, strReplace) |
102 else: |
104 else: |
103 return (False, statement) |
105 return (False, statement, strReplace) |
104 |
106 |
105 |
107 |
106 def checkHardcodedSqlExpressions(reportError, context, config): # noqa: U100 |
108 def checkHardcodedSqlExpressions(reportError, context, config): # noqa: U100 |
107 """ |
109 """ |
108 Function to check for SQL injection. |
110 Function to check for SQL injection. |
112 @param context security context object |
114 @param context security context object |
113 @type SecurityContext |
115 @type SecurityContext |
114 @param config dictionary with configuration data |
116 @param config dictionary with configuration data |
115 @type dict |
117 @type dict |
116 """ |
118 """ |
117 val = _evaluateAst(context.node) |
119 executeCall, statement, strReplace = _evaluateAst(context.node) |
118 if _checkString(val[1]): |
120 if _checkString(statement): |
119 reportError( |
121 reportError( |
120 context.node.lineno - 1, |
122 context.node.lineno - 1, |
121 context.node.col_offset, |
123 context.node.col_offset, |
122 "S608", |
124 "S608", |
123 "M", |
125 "M", |
124 "M" if val[0] else "L", |
126 "M" if executeCall and not strReplace else "L", |
125 ) |
127 ) |