99 print ("Warning: javalang library not found. Source code extraction may be limited." )
1010 javalang = None
1111
12+ # 加载Source-Sink分类配置
13+ def load_sink_categories (file_path ):
14+ categories = {}
15+ current_category = "其他漏洞"
16+
17+ if not os .path .exists (file_path ):
18+ print (f"Warning: SourcesAndSinks file not found at { file_path } " )
19+ return categories
20+
21+ try :
22+ with open (file_path , 'r' , encoding = 'utf-8' ) as f :
23+ for line in f :
24+ line = line .strip ()
25+ if not line :
26+ continue
27+
28+ if line .startswith ('#' ):
29+ # 提取注释作为分类,去除 # 和可能的说明
30+ comment = line .lstrip ('#' ).strip ()
31+ # 去除括号及后面的内容(通常是说明)
32+ if '(' in comment :
33+ comment = comment .split ('(' )[0 ]
34+ elif '(' in comment :
35+ comment = comment .split ('(' )[0 ]
36+
37+ # 忽略Source的注释头
38+ if "Source" in comment or "数据源点" in comment or "检测规则" in comment :
39+ continue
40+
41+ current_category = comment .strip ()
42+
43+ elif '-> _SINK_' in line :
44+ # 提取方法签名
45+ parts = line .split ('->' )
46+ if len (parts ) > 0 :
47+ method_sig = parts [0 ].strip ()
48+ categories [method_sig ] = current_category
49+ except Exception as e :
50+ print (f"Error loading sink categories: { e } " )
51+
52+ return categories
53+
1254# 漏洞类型分类
13- def classify_vulnerability (sink_method , sink_def ):
14- if 'TheftOverwriteProvider' in sink_method :
15- return 'ContentProvider文件读写漏洞' , '高'
16- elif 'startActivity' in sink_def or 'startService' in sink_def or 'bindService' in sink_def :
17- if 'DeeplinkActivity' in sink_method :
18- return 'Intent重定向漏洞' , '高'
19- else :
20- return 'LaunchAnyWhere漏洞' , '中'
21- elif 'WebView' in sink_def or 'WebSettings' in sink_def :
22- return 'WebView漏洞' , '高'
23- elif 'SharedPreferences' in sink_def :
24- return '信息泄露漏洞' , '中'
25- elif 'exec' in sink_def or 'Runtime' in sink_def :
26- return '命令执行漏洞' , '高'
27- elif 'reflect' in sink_def .lower () or 'Method' in sink_def and 'invoke' in sink_def :
28- return '反射漏洞' , '高'
55+ def classify_vulnerability (sink_method , sink_def , sink_categories = None ):
56+ vuln_type = '其他漏洞'
57+ severity = '低'
58+ # 1. 优先使用配置文件中的分类 (Source-Sink映射)
59+ if sink_categories and sink_def in sink_categories :
60+ vuln_type = sink_categories [sink_def ]
2961 else :
30- return '其他漏洞' , '低'
62+ # 如果找不到映射,不再尝试任何启发式分类,直接标记为其他漏洞
63+ # 这样确保所有分类都来自Source-Sink文件的定义
64+ pass
65+ # 3. 确定风险等级
66+ if any (k in vuln_type for k in ['命令执行' , '反射' , '文件读写' , 'Intent重定向' ]):
67+ severity = '高'
68+ elif any (k in vuln_type for k in ['广播漏洞' , 'LaunchAnyWhere' , '沙箱文件' , 'WebView' , 'Provider' ]):
69+ severity = '中'
70+ return vuln_type , severity
3171
3272# 生成修复建议
3373def generate_fix_advice (vuln_type ):
3474 advice_map = {
35- 'ContentProvider文件读写漏洞 ' : [
75+ 'Provider漏洞 ' : [
3676 '对Uri的lastPathSegment进行严格验证' ,
3777 '限制可访问的文件路径范围' ,
3878 '实施文件权限检查' ,
3979 '使用应用专用目录而非外部存储'
4080 ],
41- 'Intent重定向漏洞 ' : [
81+ 'Intent重定向 ' : [
4282 '对deeplink参数进行白名单验证' ,
4383 '限制可重定向的URL范围' ,
4484 '实施Intent校验机制' ,
@@ -56,23 +96,41 @@ def generate_fix_advice(vuln_type):
5696 '设置合理的WebSettings配置' ,
5797 '使用WebView安全最佳实践'
5898 ],
59- '信息泄露漏洞' : [
60- '避免在SharedPreferences中存储敏感信息' ,
61- '对存储的敏感信息进行加密' ,
62- '使用系统密钥库存储敏感数据' ,
63- '定期清理不需要的存储数据'
99+ '文件读写漏洞' : [
100+ '避免使用外部存储存储敏感数据' ,
101+ '验证文件路径以防止路径遍历' ,
102+ '使用应用私有目录' ,
103+ '对写入的文件内容进行加密'
104+ ],
105+ '广播漏洞' : [
106+ '限制广播接收者的导出属性' ,
107+ '对接收到的Intent进行校验' ,
108+ '使用LocalBroadcastManager' ,
109+ '设置广播权限'
110+ ],
111+ '沙箱文件篡改漏洞' : [
112+ '避免在SharedPreferences中存储敏感明文' ,
113+ '使用EncryptedSharedPreferences' ,
114+ '正确设置文件访问模式(MODE_PRIVATE)' ,
115+ '定期清理敏感数据'
116+ ],
117+ 'Settings Provider篡改漏洞' : [
118+ '避免修改系统全局设置' ,
119+ '检查修改设置的权限' ,
120+ '验证写入设置的值' ,
121+ '遵循Android安全最佳实践'
64122 ],
65123 '命令执行漏洞' : [
66124 '避免使用Runtime.exec等危险方法' ,
67125 '对输入参数进行严格验证' ,
68126 '使用安全的替代方案' ,
69127 '实施最小权限原则'
70128 ],
71- '反射漏洞 ' : [
72- '避免使用反射执行未知代码 ' ,
73- '对反射调用的目标进行验证 ' ,
74- '使用安全的替代方案 ' ,
75- '实施权限检查 '
129+ '反射导致RCE漏洞 ' : [
130+ '避免使用反射执行外部可控代码 ' ,
131+ '对反射调用的目标类和方法进行白名单验证 ' ,
132+ '限制反射调用的权限 ' ,
133+ '使用非反射的替代实现 '
76134 ],
77135 '其他漏洞' : [
78136 '对输入进行严格验证' ,
@@ -385,6 +443,13 @@ def parse_flowdroid_result(input_file, output_file, source_dir=None):
385443 print (f"错误: 文件 { input_file } 不存在" )
386444 return 1
387445
446+ # 加载Sink分类
447+ script_dir = os .path .dirname (os .path .abspath (__file__ ))
448+ sink_file = os .path .join (script_dir , 'SourcesAndSinks.txt' )
449+ sink_categories = load_sink_categories (sink_file )
450+ if sink_categories :
451+ print (f"已加载 { len (sink_categories )} 条Sink分类规则" )
452+
388453 try :
389454 # 解析XML文件
390455 tree = ET .parse (input_file )
@@ -423,7 +488,7 @@ def parse_flowdroid_result(input_file, output_file, source_dir=None):
423488 if sink is not None :
424489 sink_method = sink .get ('Method' , '' )
425490 sink_def = sink .get ('MethodSourceSinkDefinition' , '' )
426- vuln_type , severity = classify_vulnerability (sink_method , sink_def )
491+ vuln_type , severity = classify_vulnerability (sink_method , sink_def , sink_categories )
427492 key = (vuln_type , severity )
428493 vuln_stats [key ] = vuln_stats .get (key , 0 ) + 1
429494
@@ -452,7 +517,7 @@ def parse_flowdroid_result(input_file, output_file, source_dir=None):
452517 sink_line = sink .get ('LineNumber' , None )
453518
454519 # 分类漏洞
455- vuln_type , severity = classify_vulnerability (sink_method , sink_def )
520+ vuln_type , severity = classify_vulnerability (sink_method , sink_def , sink_categories )
456521
457522 # 生成漏洞标题
458523 severity_icon = '🔴' if severity == '高' else '🟡' if severity == '中' else '🟢'
0 commit comments