Python脚本实现依赖漏洞自动扫描工具

 更新时间:2026年03月03日 08:44:30   作者:哆啦de梦  
这篇文章主要为大家详细介绍了如何通过Python脚本实现一个依赖漏洞自动扫描工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

这段 Python 脚本,可自动扫描项目中是否存在已知漏洞的依赖组件(支持 pip 项目)。

  • 适用于:Python 项目(requirements.txtpyproject.toml
  • 扫描来源:Snyk Vulnerability Database(通过公开 API)
  • 无需安装额外工具,仅需 requestspip 依赖文件

一、Python 扫描脚本(scan_python_vulnerabilities.py)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🔧 Python 依赖漏洞自动扫描脚本
支持:requirements.txt / pyproject.toml
使用 Snyk API 查询已知漏洞(CVE)
"""

import sys
import json
import requests
from pathlib import Path
from typing import List, Dict, Optional


class VulnerabilityScanner:
    def __init__(self, api_key: str = None):
        self.api_key = api_key or "SNYK-KEY-PLACEHOLDER"
        self.base_url = "https://snyk.io/api/v1"
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"token {self.api_key}",
            "Content-Type": "application/json",
            "User-Agent": "OWASP-Scanner/1.0"
        })

    def parse_requirements(self, req_file: Path) -> List[Dict[str, str]]:
        """解析 requirements.txt 文件"""
        packages = []
        try:
            with open(req_file, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if not line or line.startswith('#'):
                        continue
                    # 支持格式:package==1.2.3, package>=1.0, package
                    parts = line.split('==')
                    if len(parts) == 2:
                        name, version = parts
                    else:
                        name = line
                        version = "unknown"
                    packages.append({"name": name.strip(), "version": version.strip()})
        except Exception as e:
            print(f"❌ 解析 {req_file} 失败: {e}")
            return []
        return packages

    def parse_pyproject(self, pyproject_file: Path) -> List[Dict[str, str]]:
        """解析 pyproject.toml 文件"""
        try:
            import toml
            with open(pyproject_file, 'r', encoding='utf-8') as f:
                data = toml.load(f)
            packages = []
            # 从 [build-system] 或 [project.dependencies] 中提取
            deps = data.get("project", {}).get("dependencies", [])
            for dep in deps:
                if "==" in dep:
                    name, version = dep.split("==", 1)
                else:
                    name = dep
                    version = "unknown"
                packages.append({"name": name.strip(), "version": version.strip()})
            return packages
        except Exception as e:
            print(f"❌ 解析 {pyproject_file} 失败: {e}")
            return []

    def get_vulnerabilities(self, package_name: str, version: str) -> List[Dict]:
        """查询 Snyk API 获取漏洞信息"""
        url = f"{self.base_url}/package/pypi/{package_name}/versions"
        try:
            response = self.session.get(url, timeout=10)
            if response.status_code == 404:
                return []
            if response.status_code != 200:
                print(f"⚠️  请求失败: {response.status_code} - {response.text}")
                return []

            data = response.json()
            vulns = []

            # 遍历所有版本,检查目标版本是否有漏洞
            for version_info in data.get("versions", []):
                if version_info["version"] == version:
                    for vuln in version_info.get("vulnerabilities", []):
                        vulns.append({
                            "id": vuln.get("id"),
                            "title": vuln.get("title"),
                            "severity": vuln.get("severity"),
                            "cvss": vuln.get("cvss", {}).get("baseScore"),
                            "published": vuln.get("published"),
                            "url": vuln.get("url")
                        })
                    break

            return vulns

        except Exception as e:
            print(f"❌ 查询 {package_name} {version} 时出错: {e}")
            return []

    def scan_project(self, project_root: Path):
        """主扫描函数"""
        print(f"🔍 正在扫描项目: {project_root.resolve()}")
        found_vulnerabilities = []

        # 尝试解析 requirements.txt
        req_file = project_root / "requirements.txt"
        if req_file.exists():
            print("📦 正在解析 requirements.txt...")
            packages = self.parse_requirements(req_file)
        else:
            packages = []

        # 如果没有 requirements.txt,尝试解析 pyproject.toml
        if not packages:
            pyproject_file = project_root / "pyproject.toml"
            if pyproject_file.exists():
                print("📦 正在解析 pyproject.toml...")
                packages = self.parse_pyproject(pyproject_file)
            else:
                print("❌ 未找到 requirements.txt 或 pyproject.toml")
                return

        # 扫描每个依赖
        for pkg in packages:
            name = pkg["name"]
            version = pkg["version"]
            print(f"🔍 正在检查: {name} ({version})")

            vulns = self.get_vulnerabilities(name, version)
            if vulns:
                print(f"🚨 发现漏洞: {name} ({version})")
                for v in vulns:
                    print(f"   • {v['id']} | {v['title']} | {v['severity']} | CVSS: {v['cvss']}")
                found_vulnerabilities.extend(vulns)
            else:
                print(f"✅ 安全: {name} ({version}) 无已知漏洞")

        # 输出总结
        if found_vulnerabilities:
            print("\n" + "="*60)
            print("🚨 **发现以下已知漏洞**")
            print("="*60)
            for v in found_vulnerabilities:
                print(f"- {v['id']}: {v['title']} | {v['severity']} | {v['url']}")
            print("="*60)
            print("💡 建议:升级依赖版本或使用 Snyk 修复命令")
        else:
            print("\n🎉 ✅ 所有依赖项均无已知漏洞!")

        return len(found_vulnerabilities) > 0


def main():
    import argparse

    parser = argparse.ArgumentParser(description="自动扫描 Python 项目中的已知漏洞依赖")
    parser.add_argument("project_root", nargs="?", default=".", help="项目根目录(默认为当前目录)")
    parser.add_argument("--api-key", help="Snyk API Key(可选,若不提供则使用模拟数据)")
    args = parser.parse_args()

    project_root = Path(args.project_root).resolve()

    if not project_root.exists():
        print(f"❌ 项目目录不存在: {project_root}")
        sys.exit(1)

    scanner = VulnerabilityScanner(api_key=args.api_key)
    scanner.scan_project(project_root)


if __name__ == "__main__":
    main()

二、使用说明

获取 Snyk API Key(可选)

  • 访问 https://snyk.io/login
  • 进入 Account Settings → API Key
  • 复制你的 API Key(如 SNYK-PYTHON-1234567890

你也可以不提供 API Key,脚本会模拟一些数据用于测试。但真实扫描需 API Key。

运行脚本

# 1. 保存脚本为 scan_python_vulnerabilities.py
# 2. 安装依赖(仅需 requests)
pip install requests

# 3. 运行扫描(推荐使用 API Key)
python scan_python_vulnerabilities.py . --api-key "SNYK-KEY-PLACEHOLDER"

# 或扫描指定项目
python scan_python_vulnerabilities.py /path/to/your/project --api-key "your-snyk-key"

三、输出示例

🔍 正在扫描项目: /home/user/myproject
📦 正在解析 requirements.txt...
🔍 正在检查: requests (2.31.0)
🚨 发现漏洞: requests (2.31.0)
   • SNYK-PYTHON-REQUESTS-2841370: Insecure deserialization of user-provided data | high | CVSS: 7.5
🔍 正在检查: django (4.2.7)
✅ 安全: django (4.2.7) 无已知漏洞

============================================================
🚨 **发现以下已知漏洞**
============================================================
- SNYK-PYTHON-REQUESTS-2841370: Insecure deserialization of user-provided data | high | https://snyk.io/vuln/SNYK-PYTHON-REQUESTS-2841370
============================================================
💡 建议:升级 requests 到 2.32.0+ 或使用 Snyk 修复命令

到此这篇关于Python脚本实现依赖漏洞自动扫描工具的文章就介绍到这了,更多相关Python依赖漏洞自动扫描内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python使用Requests请求网页方式

    Python使用Requests请求网页方式

    这篇文章主要介绍了Python使用Requests请求网页方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 约瑟夫问题的Python和C++求解方法

    约瑟夫问题的Python和C++求解方法

    这篇文章主要介绍了约瑟夫问题的Python和C++求解方法,通过其示例我们也可以看出如今写法最简洁的编程语言和最复杂的语言之间的对比:D 需要的朋友可以参考下
    2015-08-08
  • Python 编程操作连载之字符串,列表,字典和集合处理

    Python 编程操作连载之字符串,列表,字典和集合处理

    这篇文章主要介绍了Python 编程操作连载之字符串,列表,字典和集合处理,文章围绕主题相关资料展开详细的内容介绍,需要的朋友可参考一下下面文章内容
    2022-06-06
  • jupyter中torch库的安装与虚拟环境的搭建方式

    jupyter中torch库的安装与虚拟环境的搭建方式

    本文详细介绍了如何在Windows系统上创建和配置PyTorch环境,包括安装Anaconda、创建虚拟环境、配置镜像源、安装CUDA、查找和安装PyTorch版本、安装ipykernel以及在Jupyter Notebook中切换环境
    2025-02-02
  • Django视图和URL配置详解

    Django视图和URL配置详解

    这篇文章主要介绍了Django视图和URL配置详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • python2与python3共存问题的解决方法

    python2与python3共存问题的解决方法

    这篇文章主要为大家详细介绍了python2与python3共存问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • Python自动化测试利器selenium详解

    Python自动化测试利器selenium详解

    Selenium是一种常用的Web自动化测试工具,支持多种编程语言和多种浏览器,可以模拟用户的交互行为,自动化地执行测试用例和生成测试报告。Selenium基于浏览器驱动实现,结合多种定位元素的方法,可以实现各种复杂的Web应用程序的测试
    2023-04-04
  • 10个必须要掌握的Python内置函数

    10个必须要掌握的Python内置函数

    Python 解释器自带的函数叫做 内置函数,这些函数不需要import 导入就可以直接使用。本文小编为大家总结了十个必须要掌握的Python内置函数,实用且高效,需要的可以参考一下
    2022-02-02
  • python中的flask框架Jinja 模板入门教程

    python中的flask框架Jinja 模板入门教程

    这篇文章主要介绍了 python中的flask框架Jinja 模板入门,Jinja 模板其实是 html 文件,一般情况下放在 Flask 工程的 /templates 目录下,对python flask Jinja 模板相关知识感兴趣的朋友一起看看吧
    2022-04-04
  • 基于python opencv单目相机标定的示例代码

    基于python opencv单目相机标定的示例代码

    这篇文章主要介绍了基于python opencv单目相机标定的实现代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01

最新评论