作用原理
通过 _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敏感信息辅助脚本)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论