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求已知DNA模板的互补DNA序列

    自学python求已知DNA模板的互补DNA序列

    这篇文章主要为大家介绍了自学python求已知DNA模板的互补DNA序列的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Python在cmd上打印彩色文字实现过程详解

    Python在cmd上打印彩色文字实现过程详解

    这篇文章主要介绍了Python在cmd上打印彩色文字实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Anaconda虚拟环境配置Python库与Spyder编译器的方法

    Anaconda虚拟环境配置Python库与Spyder编译器的方法

    在文章创建Anaconda虚拟Python环境的方法中,我们介绍了在Anaconda环境下,创建、使用与删除Python虚拟环境的方法,而创建虚拟环境后,就需要在对应的环境内配置各类库与软件,本文就对这些操作加以介绍,感兴趣的朋友感兴趣的朋友一起看看吧
    2024-04-04
  • Python结合JSON实现动态按钮管理程序

    Python结合JSON实现动态按钮管理程序

    这篇文章主要为大家详细介绍了如何使用Python的wxPython库结合JSON配置文件,开发一个支持动态按钮创建,文件执行和配置管理的桌面应用程序,感兴趣的可以了解下
    2025-04-04
  • Python中函数的创建与调用你了解吗

    Python中函数的创建与调用你了解吗

    这篇文章主要为大家详细介绍了Python中函数的创建与调用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • Playwright快速上手指南(入门教程)

    Playwright快速上手指南(入门教程)

    Playwright是由微软公司2020年初发布的新一代自动化测试工具,相较于目前最常用的Selenium,本文就详细的介绍一下快速上手指南,对新手有一定的帮助,感兴趣的可以了解一下
    2021-12-12
  • python插入数据到列表的方法

    python插入数据到列表的方法

    这篇文章主要介绍了python插入数据到列表的方法,涉及Python中insert方法的使用技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • Python反射用法实战完整学习笔记

    Python反射用法实战完整学习笔记

    反射就是程序在运行时能够观察自己,获取、检查和修改自身状态或行为的一种能力,这篇文章主要介绍了Python反射用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-01-01
  • Python实现局域网远程控制电脑

    Python实现局域网远程控制电脑

    这篇文章主要为大家详细介绍了如何利用Python编写一个工具,可以实现远程控制局域网电脑关机,重启,注销等功能,感兴趣的小伙伴可以参考一下
    2024-12-12
  • python 成功引入包但无法正常调用的解决

    python 成功引入包但无法正常调用的解决

    这篇文章主要介绍了python 成功引入包但无法正常调用的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03

最新评论