23 |
23 |
24 |
24 |
25 def getChecks(): |
25 def getChecks(): |
26 """ |
26 """ |
27 Public method to get a dictionary with checks handled by this module. |
27 Public method to get a dictionary with checks handled by this module. |
28 |
28 |
29 @return dictionary containing checker lists containing checker function and |
29 @return dictionary containing checker lists containing checker function and |
30 list of codes |
30 list of codes |
31 @rtype dict |
31 @rtype dict |
32 """ |
32 """ |
33 return { |
33 return { |
34 "Str": [ |
34 "Str": [ |
35 (checkHardcodedAwsKey, ("S801", "S802")), |
35 (checkHardcodedAwsKey, ("S801", "S802")), |
36 ], |
36 ], |
37 } |
37 } |
38 |
38 |
|
39 |
39 AWS_ACCESS_KEY_ID_SYMBOLS = string.ascii_uppercase + string.digits |
40 AWS_ACCESS_KEY_ID_SYMBOLS = string.ascii_uppercase + string.digits |
40 AWS_ACCESS_KEY_ID_REGEX = re.compile( |
41 AWS_ACCESS_KEY_ID_REGEX = re.compile("[" + AWS_ACCESS_KEY_ID_SYMBOLS + "]{20}") |
41 '[' + AWS_ACCESS_KEY_ID_SYMBOLS + ']{20}' |
|
42 ) |
|
43 AWS_ACCESS_KEY_ID_MAX_ENTROPY = 3 |
42 AWS_ACCESS_KEY_ID_MAX_ENTROPY = 3 |
44 |
43 |
45 AWS_SECRET_ACCESS_KEY_SYMBOLS = string.ascii_letters + string.digits + '/+=' |
44 AWS_SECRET_ACCESS_KEY_SYMBOLS = string.ascii_letters + string.digits + "/+=" |
46 AWS_SECRET_ACCESS_KEY_REGEX = re.compile( |
45 AWS_SECRET_ACCESS_KEY_REGEX = re.compile("[" + AWS_SECRET_ACCESS_KEY_SYMBOLS + "]{40}") |
47 '[' + AWS_SECRET_ACCESS_KEY_SYMBOLS + ']{40}' |
|
48 ) |
|
49 AWS_SECRET_ACCESS_KEY_MAX_ENTROPY = 4.5 |
46 AWS_SECRET_ACCESS_KEY_MAX_ENTROPY = 4.5 |
50 |
47 |
51 |
48 |
52 def shannonEntropy(data, symbols): |
49 def shannonEntropy(data, symbols): |
53 """ |
50 """ |
54 Function to caclculate the Shannon entropy of some given data. |
51 Function to caclculate the Shannon entropy of some given data. |
55 |
52 |
56 Source: |
53 Source: |
57 http://blog.dkbza.org/2007/05/scanning-data-for-entropy-anomalies.html |
54 http://blog.dkbza.org/2007/05/scanning-data-for-entropy-anomalies.html |
58 |
55 |
59 @param data data to calculate the entropy for |
56 @param data data to calculate the entropy for |
60 @type str |
57 @type str |
61 @param symbols allowed symbols |
58 @param symbols allowed symbols |
62 @type str |
59 @type str |
63 @return Shannon entropy of the given data |
60 @return Shannon entropy of the given data |
68 entropy = 0 |
65 entropy = 0 |
69 counts = Counter(data) |
66 counts = Counter(data) |
70 for x in symbols: |
67 for x in symbols: |
71 p_x = float(counts[x]) / len(data) |
68 p_x = float(counts[x]) / len(data) |
72 if p_x > 0: |
69 if p_x > 0: |
73 entropy += - p_x * math.log(p_x, 2) |
70 entropy += -p_x * math.log(p_x, 2) |
74 return entropy |
71 return entropy |
75 |
72 |
76 |
73 |
77 def checkHardcodedAwsKey(reportError, context, config): |
74 def checkHardcodedAwsKey(reportError, context, config): |
78 """ |
75 """ |
79 Function to check for potentially hardcoded AWS passwords. |
76 Function to check for potentially hardcoded AWS passwords. |
80 |
77 |
81 @param reportError function to be used to report errors |
78 @param reportError function to be used to report errors |
82 @type func |
79 @type func |
83 @param context security context object |
80 @param context security context object |
84 @type SecurityContext |
81 @type SecurityContext |
85 @param config dictionary with configuration data |
82 @param config dictionary with configuration data |
93 context.node.lineno - 1, |
90 context.node.lineno - 1, |
94 context.node.col_offset, |
91 context.node.col_offset, |
95 "S801", |
92 "S801", |
96 "L", |
93 "L", |
97 "M", |
94 "M", |
98 node.s |
95 node.s, |
99 ) |
96 ) |
100 |
97 |
101 elif AWS_SECRET_ACCESS_KEY_REGEX.fullmatch(node.s): |
98 elif AWS_SECRET_ACCESS_KEY_REGEX.fullmatch(node.s): |
102 entropy = shannonEntropy(node.s, AWS_SECRET_ACCESS_KEY_SYMBOLS) |
99 entropy = shannonEntropy(node.s, AWS_SECRET_ACCESS_KEY_SYMBOLS) |
103 if entropy > AWS_SECRET_ACCESS_KEY_MAX_ENTROPY: |
100 if entropy > AWS_SECRET_ACCESS_KEY_MAX_ENTROPY: |
104 reportError( |
101 reportError( |
105 context.node.lineno - 1, |
102 context.node.lineno - 1, |
106 context.node.col_offset, |
103 context.node.col_offset, |
107 "S802", |
104 "S802", |
108 "M", |
105 "M", |
109 "M", |
106 "M", |
110 node.s |
107 node.s, |
111 ) |
108 ) |