You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
9.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
JavaScript代码分析器
"""
import re
import os
from typing import List, Dict, Any
from .base_analyzer import BaseAnalyzer
class JavaScriptAnalyzer(BaseAnalyzer):
"""JavaScript代码分析器"""
def __init__(self):
super().__init__()
self.name = "JavaScript Analyzer"
self.version = "1.0.0"
self.supported_extensions = ["js", "jsx", "ts", "tsx"]
self.description = "JavaScript/TypeScript代码静态分析器"
async def analyze(self, project_path: str, config: Dict[str, Any] = None) -> List[Dict[str, Any]]:
"""分析JavaScript代码"""
vulnerabilities = []
# 获取所有JavaScript文件
js_files = self.get_project_files(project_path)
for file_path in js_files:
try:
# 读取文件内容
content = self.read_file_content(file_path)
if not content:
continue
lines = content.split('\n')
# 执行各种检查
vulnerabilities.extend(self._check_security_issues(lines, file_path))
vulnerabilities.extend(self._check_performance_issues(lines, file_path))
vulnerabilities.extend(self._check_maintainability_issues(lines, file_path))
except Exception as e:
# 分析错误
vulnerabilities.append(self.create_vulnerability(
rule_id="JS000",
message=f"分析错误: {str(e)}",
file_path=file_path,
severity="high",
category="reliability"
))
return vulnerabilities
def _check_security_issues(self, lines: List[str], file_path: str) -> List[Dict[str, Any]]:
"""检查安全问题"""
vulnerabilities = []
for i, line in enumerate(lines):
line_num = i + 1
line_stripped = line.strip()
# 检查eval使用
if 'eval(' in line_stripped:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS101",
message="使用eval(),存在代码注入风险",
file_path=file_path,
line_number=line_num,
severity="critical",
category="security",
code_snippet=line_stripped
))
# 检查innerHTML使用
elif 'innerHTML' in line_stripped and '=' in line_stripped:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS102",
message="使用innerHTML存在XSS风险",
file_path=file_path,
line_number=line_num,
severity="high",
category="security",
code_snippet=line_stripped
))
# 检查document.write使用
elif 'document.write(' in line_stripped:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS103",
message="使用document.write()存在XSS风险",
file_path=file_path,
line_number=line_num,
severity="high",
category="security",
code_snippet=line_stripped
))
# 检查console.log在生产环境中的使用
elif 'console.log(' in line_stripped:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS104",
message="生产环境中不应使用console.log",
file_path=file_path,
line_number=line_num,
severity="low",
category="security",
code_snippet=line_stripped
))
# 检查硬编码的敏感信息
elif re.search(r'password\s*[:=]\s*["\'][^"\']+["\']', line_stripped, re.IGNORECASE):
vulnerabilities.append(self.create_vulnerability(
rule_id="JS105",
message="代码中包含硬编码的密码",
file_path=file_path,
line_number=line_num,
severity="high",
category="security",
code_snippet=line_stripped
))
return vulnerabilities
def _check_performance_issues(self, lines: List[str], file_path: str) -> List[Dict[str, Any]]:
"""检查性能问题"""
vulnerabilities = []
for i, line in enumerate(lines):
line_num = i + 1
line_stripped = line.strip()
# 检查DOM操作在循环中
if re.search(r'for\s*\([^)]*\)\s*\{', line_stripped):
# 查找循环体中的DOM操作
for j in range(i + 1, min(i + 20, len(lines))):
loop_line = lines[j].strip()
if loop_line == '}':
break
if any(dom_op in loop_line for dom_op in ['getElementById', 'querySelector', 'appendChild']):
vulnerabilities.append(self.create_vulnerability(
rule_id="JS201",
message="循环中进行DOM操作影响性能",
file_path=file_path,
line_number=j + 1,
severity="medium",
category="performance",
code_snippet=loop_line
))
# 检查未使用的变量声明
elif line_stripped.startswith('var ') or line_stripped.startswith('let ') or line_stripped.startswith('const '):
var_name = re.search(r'(var|let|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)', line_stripped)
if var_name:
var_name = var_name.group(2)
# 检查变量是否在后续代码中使用
is_used = False
for k in range(i + 1, len(lines)):
if var_name in lines[k]:
is_used = True
break
if not is_used:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS202",
message=f"未使用的变量: {var_name}",
file_path=file_path,
line_number=line_num,
severity="low",
category="performance",
code_snippet=line_stripped
))
return vulnerabilities
def _check_maintainability_issues(self, lines: List[str], file_path: str) -> List[Dict[str, Any]]:
"""检查可维护性问题"""
vulnerabilities = []
for i, line in enumerate(lines):
line_num = i + 1
line_stripped = line.strip()
# 检查函数长度(简单检查)
if line_stripped.startswith('function ') or re.match(r'const\s+\w+\s*=\s*\([^)]*\)\s*=>', line_stripped):
# 计算函数体长度
brace_count = 0
function_start = i
for j in range(i, len(lines)):
line_content = lines[j]
brace_count += line_content.count('{')
brace_count -= line_content.count('}')
if brace_count > 0 and j > i:
continue
elif brace_count == 0 and j > i:
function_length = j - function_start
if function_length > 30:
vulnerabilities.append(self.create_vulnerability(
rule_id="JS301",
message="函数过长,建议拆分",
file_path=file_path,
line_number=line_num,
severity="medium",
category="maintainability",
code_snippet=line_stripped
))
break
# 检查深度嵌套
elif line_stripped.endswith('{'):
indent_level = len(line) - len(line.lstrip())
if indent_level > 40: # 假设每层缩进4个空格
vulnerabilities.append(self.create_vulnerability(
rule_id="JS302",
message="代码嵌套过深,影响可读性",
file_path=file_path,
line_number=line_num,
severity="low",
category="maintainability",
code_snippet=line_stripped
))
# 检查魔法数字
elif re.search(r'\b\d{3,}\b', line_stripped):
vulnerabilities.append(self.create_vulnerability(
rule_id="JS303",
message="存在魔法数字,建议使用常量",
file_path=file_path,
line_number=line_num,
severity="low",
category="maintainability",
code_snippet=line_stripped
))
return vulnerabilities