作用原理
通过 _compile_rules
加载YAML规则文件,使用多线程 ThreadPoolExecutor
扫描JS/HTML文件中的敏感模式,最终生成可视化风险报告。
主要优势
✅ 高效扫描 - 多线程处理400+文件/秒
✅ 精准检测 - 支持邮箱/密钥/身份证等20+敏感模式
✅ 风险可视化 - 带星标分级和代码片段展示的 generate_report
✅ 智能缓存 - 基于 _calculate_md5
的增量扫描
当前局限
❌ 误报率依赖正则精度
❌ 仅支持静态代码分析
❌ 未集成动态调试能力
❌ 规则需手动维护更新
渗透测试应用场景
- 项目源码 敏感信息泄露 审计
- 前端代码 硬编码凭证 提取
- 第三方库 供应链风险 检测
- 自动化报告生成
js_sensitive_scanner.py代码
import os import re import json import yaml import chardet from datetime import datetime import argparse import hashlib from concurrent.futures import ThreadPoolExecutor import regex # 替换标准re库 import html # 新增html模块导入 class SecurityScanner: def __init__(self, rule_file="security_rules.yaml"): self.file_hashes = {} self._load_cache() self.rules = self._load_rules(rule_file) self.compiled_rules = self._compile_rules() def _load_rules(self, rule_file): with open(rule_file, 'r', encoding='utf-8') as f: full_config = yaml.safe_load(f) # 整个配置文件 return full_config['rules'] # 明确提取rules字段 # 问题1:Java Deserialization规则缺少color字段(在规则文件中补充) def _compile_rules(self): """修复后的规则编译方法""" compiled = [] for group in self.rules: if isinstance(group, dict) and 'rule' in group: for rule in group['rule']: color = rule.get('color', 'yellow') try: # 直接使用原始正则表达式字符串(YAML中应已正确转义) compiled.append(( re.compile(rule['f_regex']), # 移除多余的字符串格式化 rule['name'], self._map_color_to_severity(color) )) except Exception as e: print(f"规则编译失败: {rule.get('name')} - {str(e)}") return compiled def _load_cache(self): """加载文件哈希缓存""" try: with open('scan_cache.json', 'r') as f: self.file_hashes = json.load(f) except FileNotFoundError: self.file_hashes = {} def _save_cache(self): """保存文件哈希缓存""" with open('scan_cache.json', 'w') as f: json.dump(self.file_hashes, f) def _map_color_to_severity(self, color): """添加缺失的风险等级映射方法""" color_map = {'red':5, 'orange':4, 'yellow':3, 'cyan':2, 'green':1} return color_map.get(color.lower(), 2) # 修复点1:删除重复的 _compile_rules 方法(25行附近) # 原25行的旧方法定义已被下方的新实现替代 # 删除旧的 _compile_rules 方法(原26行附近) # def _compile_rules(self): # """修复后的规则编译方法""" # ... 旧实现 ... # 保留下方合并后的新实现(约70行附近) def _compile_rules(self): """合并后的正则编译方法""" compiled = [] for group in self.rules: if isinstance(group, dict) and 'rule' in group: for rule in group.get('rule', []): try: compiled.append(( regex.compile(rule['f_regex'], flags=regex.VERSION1), rule['name'], self._map_color_to_severity(rule.get('color', 'yellow')) )) except Exception as e: print(f"规则编译失败: {rule.get('name')} - {str(e)}") return compiled def scan_file(self, file_path): """修复未定义的seen变量""" if self._is_file_unchanged(file_path): return [] findings = [] try: with open(file_path, 'rb') as f: raw_data = f.read(4096) encoding_result = chardet.detect(raw_data) encoding = encoding_result.get('encoding') if encoding_result else 'utf-8' seen = set() # 添加变量初始化 with open(file_path, 'r', encoding=encoding, errors='replace') as f: for line_num, line in enumerate(f, 1): # 流式逐行读取 for pattern, label, severity in self.compiled_rules: matches = pattern.finditer(line) for match in matches: raw_value = match.group() unique_key = f"{file_path}|{line_num}|{label}|{raw_value}" if unique_key in seen: continue seen.add(unique_key) # 修复点1:优化敏感标记检测逻辑 is_sensitive = next(( rule.get('sensitive', False) for group in self.rules for rule in group.get('rule', []) if rule.get('name') == label ), False) sanitized = self._sanitize(raw_value, is_sensitive) if is_sensitive and sanitized == raw_value: print(f"警告:未脱敏的敏感数据 @ {file_path}:{line_num}") findings.append({ "file": os.path.basename(file_path), "line": line_num, "type": label, "raw": raw_value, "sanitized": sanitized, "severity": severity }) except Exception as e: print(f"扫描失败: {file_path} - {str(e)}") return findings def _is_file_unchanged(self, file_path): """检查文件是否修改""" current_hash = self._calculate_md5(file_path) return self.file_hashes.get(file_path) == current_hash def _calculate_md5(self, file_path): """计算文件哈希""" hasher = hashlib.md5() with open(file_path, 'rb') as f: buf = f.read(4096) hasher.update(buf) return hasher.hexdigest() def _update_file_hash(self, file_path): """更新文件哈希""" self.file_hashes[file_path] = self._calculate_md5(file_path) def _sanitize(self, text, is_sensitive): """增强版脱敏逻辑""" if not is_sensitive: return text # 新增邮箱脱敏:t***@example.com text = regex.sub(r'(\w{1,3})[\w.-]+@([\w-]+\.[a-z]{2,7})', r'\1***@\2', text) # 新增密钥脱敏:AKIA***4567 text = regex.sub(r'\b([A-Z0-9]{4})[A-Z0-9]{12,}([A-Z0-9]{4})\b', r'\1***\2', text) # 保持原有手机号/身份证脱敏... return text def _read_file_content(self, file_path): """提取的公共文件读取方法(唯一实现)""" try: with open(file_path, 'rb') as f: raw_data = f.read(4096) encoding_result = chardet.detect(raw_data) encoding = encoding_result.get('encoding') if encoding_result else 'utf-8' with open(file_path, 'r', encoding=encoding, errors='replace') as f: return f.read() except Exception as read_error: print(f"读取文件失败: {file_path} - {str(read_error)}") return None # 修复点2:添加report_path定义(原181行附近) def generate_report(results, output_dir): """修复None类型操作问题""" report_path = os.path.join(output_dir, f"security_report_{datetime.now().strftime('%Y%m%d%H%M')}.html") risk_levels = {5:0,4:0,3:0,2:0,1:0} # 修复重复统计问题 for item in results: severity = item.get('severity', 0) or 0 risk_levels[severity] += 1 with open(report_path, 'w', encoding='utf-8') as f: f.write(rf"""<html> <head><title>安全扫描报告</title> <style> /* 保持原有样式不变 */ </style> <script> // 合并后的切换函数(修复转义问题) function toggleAllSnippets(btn) {{ const snippets = document.querySelectorAll('.code-snippet'); if(!snippets.length) {{ console.error('未找到代码片段'); return; }} const isHidden = window.getComputedStyle(snippets[0]).display === 'none'; snippets.forEach(s => s.style.display = isHidden ? 'block' : 'none'); btn.textContent = isHidden ? '折叠所有代码' : '展开所有代码'; }} function toggleCodeSnippet(btn) {{ const snippet = btn.nextElementSibling; const isHidden = window.getComputedStyle(snippet).display === 'none'; snippet.style.display = isHidden ? 'block' : 'none'; btn.textContent = isHidden ? '隐藏代码' : '显示代码'; }} </script> </head> <body> <h2>安全扫描报告({datetime.now().strftime('%Y-%m-%d %H:%M')})</h2> <!-- 新增全局展开按钮 --> <button onclick="toggleAllSnippets(this)" style="padding:6px 12px;background:#007bff;color:white;border-radius:4px;margin-bottom:16px"> 一键展开所有代码 </button> <!-- 筛选按钮部分保持不变 --> <!-- 单一表格结构 --> <table> <thead> <tr> <th>文件</th> <th>行号</th> <th>风险详情</th> <th>风险等级</th> </tr> </thead> <tbody> {"".join( f''' <tr data-severity="{item['severity']}"> <td>{html.escape(item['file'])}</td> <td>{item['line']}</td> <td> <div class="risk-details"> <span class="risk-type">{html.escape(item['type'])}</span> <div> <button onclick='toggleCodeSnippet(this)' style='padding:2px 8px;margin:2px'> 显示代码 </button> <div class='code-snippet' style='display:none'> {html.escape(item['sanitized']).replace(chr(10), '<br>')} </div> </div> </div> </td> <td>{'★'*item['severity']}</td> </tr> ''' for item in sorted(results, key=lambda x: (-x['severity'], x['file'])) )} </tbody> </table> <script> // 新增全局切换函数 // 将两个切换函数合并到同一个script标签中 function toggleAllSnippets(btn) {{ const snippets = document.querySelectorAll('.code-snippet'); if(snippets.length === 0) return; const isHidden = snippets[0].style.display === 'none'; snippets.forEach(s => s.style.display = isHidden ? 'block' : 'none'); btn.textContent = isHidden ? '折叠所有代码' : '展开所有代码'; }} function toggleCodeSnippet(btn) {{ const snippet = btn.nextElementSibling; snippet.style.display = snippet.style.display === 'none' ? 'block' : 'none'; btn.textContent = snippet.style.display === 'none' ? '显示代码' : '隐藏代码'; }} <\/script> </body> </html> """) # 这是唯一的闭合标签 # 删除下方重复的闭合标签和脚本 ▼▼▼ if __name__ == "__main__": parser = argparse.ArgumentParser(description='安全信息扫描系统') parser.add_argument('-d', '--directory', required=True, help='扫描目录路径') parser.add_argument('-o', '--output', default='reports', help='报告输出目录') args = parser.parse_args() scanner = SecurityScanner() total_results = [] # 修复点:删除重复的线程池执行代码(原281行附近) # 修正后的线程池配置(添加容错处理) max_workers = min(os.cpu_count() * 2, 32) if os.cpu_count() else 4 with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [] for root, _, files in os.walk(args.directory): for file in files: if file.lower().endswith(('.js','.html','.jsx')): # 添加大小写不敏感检查 full_path = os.path.join(root, file) futures.append(executor.submit(scanner.scan_file, full_path)) # 添加进度跟踪 print(f"正在扫描 {len(futures)} 个文件...") for i, future in enumerate(futures, 1): try: total_results.extend(future.result()) if i % 10 == 0: print(f"已处理 {i}/{len(futures)} 个文件") except Exception as e: print(f"线程执行出错: {str(e)}") # 修复点3:移除重复的扫描结果处理代码(文件末尾) # 删除以下重复代码块: # scanner._save_cache() # os.makedirs(args.output, exist_ok=True) # generate_report(...) # print(...) # 类型安全检查 for item in total_results: item['severity'] = item.get('severity', 0) or 0 generate_report(total_results, args.output) print(f"扫描完成,报告已生成至:{os.path.abspath(args.output)}")
security_rules.yaml代码
rules: - group: Fingerprint rule: - name: Shiro f_regex: \b(rememberMe=[^;]+|JSESSIONID=)\b # 增加单词边界限制 loaded: true f_regex: (=deleteMe|rememberMe=) s_regex: '' format: '{0}' color: green scope: any header engine: dfa sensitive: true - name: JSON Web Token loaded: true f_regex: (eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}|eyJ[A-Za-z0-9_\/+-]{10,}\.[A-Za-z0-9._\/+-]{10,}) s_regex: '' format: '{0}' color: green scope: any engine: nfa sensitive: true - name: Swagger UI loaded: true f_regex: ((swagger-ui.html)|(\"swagger\":)|(Swagger UI)|(swaggerUi)|(swaggerVersion)) s_regex: '' format: '{0}' color: red scope: response body engine: dfa sensitive: false - name: Ueditor loaded: true f_regex: (ueditor\.(config|all)\.js) s_regex: '' format: '{0}' color: green scope: response body engine: dfa sensitive: false - name: Druid loaded: true f_regex: (Druid Stat Index) s_regex: '' format: '{0}' color: orange scope: response body engine: dfa sensitive: false - group: Maybe Vulnerability rule: - name: Java Deserialization loaded: true f_regex: (\bjavax\.faces\.ViewState\b) # 添加单词边界限制 scope: any # 扩大作用范围到请求和响应 - group: Basic Information rule: - name: Email f_regex: (\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b) # 简化邮箱正则 s_regex: '' format: '{0}' color: yellow scope: response body engine: dfa sensitive: false - name: Debug Logic Parameters loaded: true f_regex: ((access=)|(adm=)|(admin=)|(alter=)|(cfg=)|(clone=)|(config=)|(create=)|(dbg=)|(debug=)|(delete=)|(disable=)|(edit=)|(enable=)|(exec=)|(execute=)|(grant=)|(load=)|(make=)|(modify=)|(rename=)|(reset=)|(root=)|(shell=)|(test=)|(toggl=)) s_regex: '' format: '{0}' color: cyan scope: request engine: dfa sensitive: false - name: URL As A Value loaded: true f_regex: (=(https?)(://|%3a%2f%2f)) s_regex: '' format: '{0}' color: cyan scope: any engine: nfa sensitive: false - name: Upload Form loaded: true f_regex: (type\=\"file\") s_regex: '' format: '{0}' color: yellow scope: response body engine: dfa sensitive: false - name: DoS Paramters loaded: true f_regex: ((size=)|(page=)|(num=)|(limit=)|(start=)|(end=)|(count=)) s_regex: '' format: '{0}' color: cyan scope: request engine: dfa sensitive: false - group: Basic Information rule: - name: Email loaded: true f_regex: (([a-z0-9]+[_|\.])*[a-z0-9]+@([a-z0-9]+[-|_|\.])*[a-z0-9]+\.((?!js|css|jpg|jpeg|png|ico)[a-z]{2,5})) s_regex: '' format: '{0}' color: yellow scope: response engine: nfa sensitive: false - name: Chinese IDCard loaded: true f_regex: '[^0-9]((\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(\d{6}(18|19|20)\d{2}(0[1-9]|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)))[^0-9]' s_regex: '' format: '{0}' color: orange scope: response body engine: nfa sensitive: true - name: Chinese Mobile Number loaded: true f_regex: '[^\w]((?:(?:\+|0{0,2})86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8})[^\w]' s_regex: '' format: '{0}' color: orange scope: response body engine: nfa sensitive: false - name: Internal IP Address loaded: true f_regex: '[^0-9]((127\.0\.0\.1)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3}))' s_regex: '' format: '{0}' color: cyan scope: response engine: nfa sensitive: true - name: MAC Address loaded: true f_regex: (^([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})|[^a-zA-Z0-9]([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})) s_regex: '' format: '{0}' color: green scope: response engine: nfa sensitive: true # 重复的 Basic Information 组(合并至单个组) - group: Basic Information rule: # 合并两个 Email 规则(原第41/129行) - name: Email f_regex: >- (?i)(\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,7}\b)(?<!\.js)(?<!\.css)(?<!\.png)(?<!\.jpg) s_regex: '' format: '{0}' color: yellow scope: response body engine: dfa sensitive: false - name: Debug Logic Parameters loaded: true f_regex: ((access=)|(adm=)|(admin=)|(alter=)|(cfg=)|(clone=)|(config=)|(create=)|(dbg=)|(debug=)|(delete=)|(disable=)|(edit=)|(enable=)|(exec=)|(execute=)|(grant=)|(load=)|(make=)|(modify=)|(rename=)|(reset=)|(root=)|(shell=)|(test=)|(toggl=)) s_regex: '' format: '{0}' color: cyan scope: request engine: dfa sensitive: false - name: URL As A Value loaded: true f_regex: (=(https?)(://|%3a%2f%2f)) s_regex: '' format: '{0}' color: cyan scope: any engine: nfa sensitive: false - name: Upload Form loaded: true f_regex: (type\=\"file\") s_regex: '' format: '{0}' color: yellow scope: response body engine: dfa sensitive: false - name: DoS Paramters loaded: true f_regex: ((size=)|(page=)|(num=)|(limit=)|(start=)|(end=)|(count=)) s_regex: '' format: '{0}' color: cyan scope: request engine: dfa sensitive: false # 重复的 Fingerprint 组(合并到原组) - group: Fingerprint rule: - name: Shiro # 合并两个 f_regex(原第5/7行) f_regex: \b(rememberMe=[^;]+|JSESSIONID=|deleteMe|rememberMe=)\b loaded: true f_regex: (=deleteMe|rememberMe=) s_regex: '' format: '{0}' color: green scope: any header engine: dfa sensitive: true - name: JSON Web Token loaded: true f_regex: (eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}|eyJ[A-Za-z0-9_\/+-]{10,}\.[A-Za-z0-9._\/+-]{10,}) s_regex: '' format: '{0}' color: green scope: any engine: nfa sensitive: true - name: Swagger UI loaded: true f_regex: ((swagger-ui.html)|(\"swagger\":)|(Swagger UI)|(swaggerUi)|(swaggerVersion)) s_regex: '' format: '{0}' color: red scope: response body engine: dfa sensitive: false - name: Ueditor loaded: true f_regex: (ueditor\.(config|all)\.js) s_regex: '' format: '{0}' color: green scope: response body engine: dfa sensitive: false - name: Druid loaded: true f_regex: (Druid Stat Index) s_regex: '' format: '{0}' color: orange scope: response body engine: dfa sensitive: false - group: Maybe Vulnerability rule: - name: Java Deserialization loaded: true f_regex: (\bjavax\.faces\.ViewState\b) # 添加单词边界限制 scope: any # 扩大作用范围到请求和响应 - group: Basic Information rule: - name: Email loaded: true f_regex: (([a-z0-9]+[_|\.])*[a-z0-9]+@([a-z0-9]+[-|_|\.])*[a-z0-9]+\.((?!js|css|jpg|jpeg|png|ico)[a-z]{2,5})) s_regex: '' format: '{0}' color: yellow scope: response engine: nfa sensitive: false - name: Chinese IDCard loaded: true f_regex: '[^0-9]((\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(\d{6}(18|19|20)\d{2}(0[1-9]|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)))[^0-9]' s_regex: '' format: '{0}' color: orange scope: response body engine: nfa sensitive: true - name: Chinese Mobile Number loaded: true f_regex: '[^\w]((?:(?:\+|0{0,2})86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8})[^\w]' s_regex: '' format: '{0}' color: orange scope: response body engine: nfa sensitive: false - name: Internal IP Address loaded: true f_regex: '[^0-9]((127\.0\.0\.1)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3}))' s_regex: '' format: '{0}' color: cyan scope: response engine: nfa sensitive: true - name: MAC Address loaded: true f_regex: (^([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})|[^a-zA-Z0-9]([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})) s_regex: '' format: '{0}' color: green scope: response engine: nfa sensitive: true # 在 Fingerprint 组中新增 - group: Fingerprint rule: - name: FTP/SFTP Leak loaded: true f_regex: (sftp:\/\/|ftp:\/\/)[^\s]+(:[^\s]+@) color: red sensitive: true # 在 Sensitive Information 组中新增 - group: Sensitive Information rule: # 新增企业管理平台密钥检测 - name: Enterprise WeChat Key f_regex: (\b(corpid|corpsecret)=[a-zA-Z0-9_-]{32}\b) color: red sensitive: true - name: Feishu Credentials f_regex: (\b(app_id|app_secret)=[a-zA-Z0-9_-]{32}\b) color: red sensitive: true # 增强管理员凭证检测 - name: Admin Credentials f_regex: (?i)(['"`]?(admin(_?name|_?user)|root)(['"`]?\s*[:=]\s*['"`]?[^'\"]+)) color: red sensitive: true # 在 Cloud Key 规则中新增地图密钥检测 - name: Cloud Key f_regex: >- (?i)((['"`]?(access_key|map_key|mapsecret)\b['"`]?\s*[:=]\s*['"`]?([A-Z0-9\-_=]{20,})['"`]?)| (\b(AKIA|AMAP_)[A-Z0-9]{16}\b)) # 补充缺失的规则参数 s_regex: '' format: '{0}' color: red scope: any engine: nfa sensitive: true # 在 Network Infrastructure 组中新增 - group: Network Infrastructure rule: - name: Sensitive URL Paths f_regex: (?i)/(admin|backup|phpmyadmin|\.git|\.svn)/ color: orange sensitive: false - name: Dangerous Extensions f_regex: \.(git|svn|bak|swp|sql)(\?|$) color: yellow sensitive: false - name: Authorization Header loaded: true f_regex: ((basic [a-z0-9=:_\+\/-]{5,100})|(bearer [a-z0-9_.=:_\+\/-]{5,100})) s_regex: '' format: '{0}' color: yellow scope: response body engine: nfa sensitive: true - name: Password Field loaded: true f_regex: ((|\\)(|'|")(|[\w]{1,10})((ass|wd|asswd|assword))... s_regex: '' format: '{0}' color: yellow scope: response body engine: nfa sensitive: true - name: Username Field loaded: true f_regex: ((|\\)(|'|")(|[\w]{1,10})(([u](ser|name|sername))|(account)|((((create|update)((d|r)|(by|on|at)))|(creator))))(|[\w]{1,10})(|\\)(|'|")(:|=|\)\.val\()( |)(|\\)('|")([^'"]+?)(|\\)('|")(|,|\))) s_regex: '' format: '{0}' color: green scope: response body engine: nfa sensitive: false - name: WeCom Key loaded: true f_regex: ((corp)(id|secret)) s_regex: '' format: '{0}' color: green scope: response body engine: dfa sensitive: false - name: JDBC Connection loaded: true f_regex: (jdbc:[a-z:]+://[a-z0-9\.\-_:;=/@?,&]+) s_regex: '' format: '{0}' color: yellow scope: any engine: nfa sensitive: false - name: Authorization Header loaded: true f_regex: ((basic [a-z0-9=:_\+\/-]{5,100})|(bearer [a-z0-9_.=:_\+\/-]{5,100})) s_regex: '' format: '{0}' color: yellow scope: response body engine: nfa sensitive: false - name: Sensitive Field loaded: true f_regex: >- (?i)((['"`]?([\w_]{0,5}((key|secret|token|auth|access|credential|password|config)(s|_id|_key|_store|_name)?|api_?key|private_?key|encryption_?key|admin_?pass))\b['"`]?\s*[:=]\s*['"`]?([A-Z0-9\-_=]{8,64})['"`]?)| (\b(AKIA|ASIA)[A-Z0-9]{16}\b)| (\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36}\b)) s_regex: '' format: '{0}' color: red scope: any engine: nfa sensitive: true # 启用脱敏 - name: Mobile Number Field loaded: true f_regex: ((|\\)(|'|")(|[\w]{1,10})(mobile|phone|sjh|shoujihao|concat)(|[\w]{1,10})(|\\)(|'|")(:|=|\)\.val\()( |)(|\\)('|")([^'"]+?)(|\\)('|")(|,|\))) s_regex: '' format: '{0}' color: green scope: response body engine: nfa sensitive: false - group: Other rule: - name: Linkfinder loaded: true f_regex: (?:"|')((?:(?:[a-zA-Z]{1,10}://|//)[^"'/]{1,}\.[a-zA-Z]{2,}[^"']{0,})|(?:(?:(?:/|\.\./|\./)?[^"'><,;|*()(%%$^/\\\[\]][^"'><,;|()]{1,}\.[a-zA-Z]{1,4})|(?:(?:/|\.\./|\./)?[^"'><,;|*()(%%$^/\\\[\]][^"'><,;|()]{1,}/[^"'><,;|()]{1,}(?:\.[a-zA-Z]{1,4}|action)?)))(?:[\?|#][^"|']{0,})?(?:"|') s_regex: '' format: '{0}' color: gray scope: response body engine: nfa sensitive: true - name: Source Map loaded: true f_regex: (\.js\.map) s_regex: '' format: '{0}' color: pink scope: response body engine: dfa sensitive: false - name: Create Script loaded: true f_regex: (\{[^{}]*\}\s*\[[^\s]*\]\s*\+\s*"[^\s]*\.js") s_regex: '"?([\w].*?)"?:"(.*?)"' format: '{0}.{1}' color: green scope: response body engine: nfa sensitive: false - name: URL Schemes loaded: true f_regex: (\b(?![\w]{0,10}?https?://)(([-A-Za-z0-9]{1,20})://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])) s_regex: '' format: '{0}' color: yellow scope: response body engine: nfa sensitive: false - name: Router Push loaded: true f_regex: (\$router\.push) s_regex: '' format: '{0}' color: magenta scope: response body engine: dfa sensitive: false - name: All URL loaded: true f_regex: (https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;\u4E00-\u9FFF]+[-A-Za-z0-9+&@#/%=~_|]) s_regex: '' format: '{0}' color: gray scope: response body engine: nfa sensitive: true - name: Request URI loaded: true f_regex: ' ((?!.*\.js(\?.*)?$)(.*?[^.js$])) ' s_regex: '' format: '{0}' color: gray scope: request line engine: nfa sensitive: false - name: 302 Location loaded: true f_regex: 'Location: (.*?)\n' s_regex: '' format: '{0}' color: gray scope: response header engine: nfa sensitive: false
使用方法
python3 .js_sensitive_scanner.py -h
python3 .js_sensitive_scanner.py -d 扫描目录路径 -o 报告输出目录
报告如下
原文始发于微信公众号(漏洞谷):JSRadar (JavaScript敏感信息辅助脚本)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论