src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
16 16
17 class SecurityChecker: 17 class SecurityChecker:
18 """ 18 """
19 Class implementing a checker for security issues. 19 Class implementing a checker for security issues.
20 """ 20 """
21
21 Codes = [ 22 Codes = [
22 # assert used 23 # assert used
23 "S101", 24 "S101",
24
25 # exec used 25 # exec used
26 "S102", 26 "S102",
27
28 # bad file permissions 27 # bad file permissions
29 "S103", 28 "S103",
30
31 # bind to all interfaces 29 # bind to all interfaces
32 "S104", 30 "S104",
33
34 # hardcoded passwords 31 # hardcoded passwords
35 "S105", "S106", "S107" 32 "S105",
36 33 "S106",
34 "S107"
37 # hardcoded tmp directory 35 # hardcoded tmp directory
38 "S108", 36 "S108",
39
40 # try-except 37 # try-except
41 "S110", "S112", 38 "S110",
42 39 "S112",
43 # flask app 40 # flask app
44 "S201", 41 "S201",
45
46 # insecure function calls (blacklisted) 42 # insecure function calls (blacklisted)
47 "S301", "S302", "S303", "S304", "S305", "S306", "S307", "S308", "S309", 43 "S301",
48 "S310", "S311", "S312", "S313", "S314", "S315", "S316", "S317", "S318", 44 "S302",
49 "S319", "S320", "S321", "S322", "S323", "S324", 45 "S303",
50 46 "S304",
47 "S305",
48 "S306",
49 "S307",
50 "S308",
51 "S309",
52 "S310",
53 "S311",
54 "S312",
55 "S313",
56 "S314",
57 "S315",
58 "S316",
59 "S317",
60 "S318",
61 "S319",
62 "S320",
63 "S321",
64 "S322",
65 "S323",
66 "S324",
51 # hashlib.new 67 # hashlib.new
52 "S331", 68 "S331",
53
54 # insecure imports (blacklisted) 69 # insecure imports (blacklisted)
55 "S401", "S402", "S403", "S404", "S405", "S406", "S407", "S408", "S409", 70 "S401",
56 "S410", "S411", "S412", "S413", 71 "S402",
57 72 "S403",
73 "S404",
74 "S405",
75 "S406",
76 "S407",
77 "S408",
78 "S409",
79 "S410",
80 "S411",
81 "S412",
82 "S413",
58 # insecure certificate usage 83 # insecure certificate usage
59 "S501", 84 "S501",
60
61 # insecure SSL/TLS protocol version 85 # insecure SSL/TLS protocol version
62 "S502", "S503", "S504", 86 "S502",
63 87 "S503",
88 "S504",
64 # weak cryptographic keys 89 # weak cryptographic keys
65 "S505", 90 "S505",
66
67 # YAML load 91 # YAML load
68 "S506", 92 "S506",
69
70 # SSH host key verification 93 # SSH host key verification
71 "S507", 94 "S507",
72
73 # Shell injection 95 # Shell injection
74 "S601", "S602", "S603", "S604", "S605", "S606", "S607", 96 "S601",
75 97 "S602",
98 "S603",
99 "S604",
100 "S605",
101 "S606",
102 "S607",
76 # SQL injection 103 # SQL injection
77 "S608", 104 "S608",
78
79 # Wildcard injection 105 # Wildcard injection
80 "S609", 106 "S609",
81
82 # Django SQL injection 107 # Django SQL injection
83 "S610", "S611", 108 "S610",
84 109 "S611",
85 # Jinja2 templates 110 # Jinja2 templates
86 "S701", 111 "S701",
87
88 # Mako templates 112 # Mako templates
89 "S702", 113 "S702",
90
91 # Django XSS vulnerability 114 # Django XSS vulnerability
92 "S703", 115 "S703",
93
94 # hardcoded AWS passwords 116 # hardcoded AWS passwords
95 "S801", "S802", 117 "S801",
118 "S802",
96 ] 119 ]
97 120
98 def __init__(self, source, filename, tree, select, ignore, expected, 121 def __init__(self, source, filename, tree, select, ignore, expected, repeat, args):
99 repeat, args):
100 """ 122 """
101 Constructor 123 Constructor
102 124
103 @param source source code to be checked 125 @param source source code to be checked
104 @type list of str 126 @type list of str
105 @param filename name of the source file 127 @param filename name of the source file
106 @type str 128 @type str
107 @param tree AST tree of the source code 129 @param tree AST tree of the source code
116 @type bool 138 @type bool
117 @param args dictionary of arguments for the security checks 139 @param args dictionary of arguments for the security checks
118 @type dict 140 @type dict
119 """ 141 """
120 self.__select = tuple(select) 142 self.__select = tuple(select)
121 self.__ignore = ('',) if select else tuple(ignore) 143 self.__ignore = ("",) if select else tuple(ignore)
122 self.__expected = expected[:] 144 self.__expected = expected[:]
123 self.__repeat = repeat 145 self.__repeat = repeat
124 self.__filename = filename 146 self.__filename = filename
125 self.__source = source[:] 147 self.__source = source[:]
126 self.__tree = copy.deepcopy(tree) 148 self.__tree = copy.deepcopy(tree)
127 self.__args = args 149 self.__args = args
128 150
129 # statistics counters 151 # statistics counters
130 self.counters = {} 152 self.counters = {}
131 153
132 # collection of detected errors 154 # collection of detected errors
133 self.errors = [] 155 self.errors = []
134 156
135 checkersWithCodes = Checks.generateCheckersDict() 157 checkersWithCodes = Checks.generateCheckersDict()
136 158
137 self.__checkers = collections.defaultdict(list) 159 self.__checkers = collections.defaultdict(list)
138 for checkType, checkersList in checkersWithCodes.items(): 160 for checkType, checkersList in checkersWithCodes.items():
139 for checker, codes in checkersList: 161 for checker, codes in checkersList:
140 if any(not (code and self.__ignoreCode(code)) 162 if any(not (code and self.__ignoreCode(code)) for code in codes):
141 for code in codes):
142 self.__checkers[checkType].append(checker) 163 self.__checkers[checkType].append(checker)
143 164
144 def __ignoreCode(self, code): 165 def __ignoreCode(self, code):
145 """ 166 """
146 Private method to check if the message code should be ignored. 167 Private method to check if the message code should be ignored.
147 168
148 @param code message code to check for 169 @param code message code to check for
149 @type str 170 @type str
150 @return flag indicating to ignore the given code 171 @return flag indicating to ignore the given code
151 @rtype bool 172 @rtype bool
152 """ 173 """
153 return (code.startswith(self.__ignore) and 174 return code.startswith(self.__ignore) and not code.startswith(self.__select)
154 not code.startswith(self.__select)) 175
155 176 def reportError(self, lineNumber, offset, code, severity, confidence, *args):
156 def reportError(self, lineNumber, offset, code, severity, confidence,
157 *args):
158 """ 177 """
159 Public method to record an issue. 178 Public method to record an issue.
160 179
161 @param lineNumber line number of the issue 180 @param lineNumber line number of the issue
162 @type int 181 @type int
163 @param offset position within line of the issue 182 @param offset position within line of the issue
164 @type int 183 @type int
165 @param code message code 184 @param code message code
173 @param args arguments for the message 192 @param args arguments for the message
174 @type list 193 @type list
175 """ 194 """
176 if self.__ignoreCode(code): 195 if self.__ignoreCode(code):
177 return 196 return
178 197
179 if code in self.counters: 198 if code in self.counters:
180 self.counters[code] += 1 199 self.counters[code] += 1
181 else: 200 else:
182 self.counters[code] = 1 201 self.counters[code] = 1
183 202
184 # Don't care about expected codes 203 # Don't care about expected codes
185 if code in self.__expected: 204 if code in self.__expected:
186 return 205 return
187 206
188 if code and (self.counters[code] == 1 or self.__repeat): 207 if code and (self.counters[code] == 1 or self.__repeat):
189 # record the issue with one based line number 208 # record the issue with one based line number
190 self.errors.append({ 209 self.errors.append(
191 "file": self.__filename, 210 {
192 "line": lineNumber + 1, 211 "file": self.__filename,
193 "offset": offset, 212 "line": lineNumber + 1,
194 "code": code, 213 "offset": offset,
195 "args": args, 214 "code": code,
196 "severity": severity, 215 "args": args,
197 "confidence": confidence, 216 "severity": severity,
198 }) 217 "confidence": confidence,
199 218 }
219 )
220
200 def getConfig(self): 221 def getConfig(self):
201 """ 222 """
202 Public method to get the configuration dictionary. 223 Public method to get the configuration dictionary.
203 224
204 @return dictionary containing the configuration 225 @return dictionary containing the configuration
205 @rtype dict 226 @rtype dict
206 """ 227 """
207 return self.__args 228 return self.__args
208 229
209 def run(self): 230 def run(self):
210 """ 231 """
211 Public method to check the given source against security related 232 Public method to check the given source against security related
212 conditions. 233 conditions.
213 """ 234 """
214 if not self.__filename: 235 if not self.__filename:
215 # don't do anything, if essential data is missing 236 # don't do anything, if essential data is missing
216 return 237 return
217 238
218 if not self.__checkers: 239 if not self.__checkers:
219 # don't do anything, if no codes were selected 240 # don't do anything, if no codes were selected
220 return 241 return
221 242
222 securityNodeVisitor = SecurityNodeVisitor( 243 securityNodeVisitor = SecurityNodeVisitor(
223 self, self.__checkers, self.__filename) 244 self, self.__checkers, self.__filename
245 )
224 securityNodeVisitor.generic_visit(self.__tree) 246 securityNodeVisitor.generic_visit(self.__tree)

eric ide

mercurial