☰
Faraday 3.15.0 版本核心能力解读:Basic Auth、CVSS/CWE/CVE 漏洞模型与工作区性能优化
2026/10/15 18:03:26 网站建设 项目流程
  • 网络安全
  • 渗透测试
  • 漏洞扫描

【免费下载链接】faraday

Open-source and AI-powered cybersecurity tools for offensive security, vulnerability management, and autonomous pentesting. Built by hackers in Latin America, used worldwide.

项目地址:https://gitcode.com/gh_mirrors/far/faraday
点击查看免费下载

Faraday 是面向攻击性安全、漏洞管理与自动化渗透测试的开源平台(2021 年 5 月 18 日发布的 3.15.0 版本变更记录见 CHANGELOG/3.15.0/community.md)。本次版本围绕"认证能力扩展、漏洞数据模型增强、工作区性能优化、代码质量收敛"四条主线展开,涉及 API 认证方式、websocket 令牌、漏洞属性列、数据库删除性能等直接影响日常使用的关键点。读完本文,你将掌握 Faraday 3.15.0 中新增的认证机制与漏洞模型字段的设计细节、对应源码实现位置,以及这些变更对部署、API 调用和漏洞管理工作流的具体影响。

一、版本定位与变更总览

3.15.0 发布于 2021 年 5 月 18 日(见 CHANGELOG/3.15.0/date.md),全部变更共 10 项,按性质归类如下:

类别变更内容
新增能力支持Basic Auth认证
新增能力websocket_tokens支持 GET 方法,POST 未来将弃用
新增能力漏洞模型与 API 新增 CVSS(String)、CWE(String)、CVE(relationship) 列
新增能力Agent token API 返回续期循环时长信息
性能优化改进数据库模型以加速工作区删除
代码质量减少 flake8 例外、统一 py3super风格、Flask app 单例化
行为约束工作区名称正则校验禁止包含正斜杠/
可观测性改进 bulk create(批量创建)日志
缺陷修复修复自有 Schema 破坏 Marshmallow 3.11.0+ 的问题
依赖升级flask_security_too升级到 4.0.0+(当前仓库主线已进一步演进,见 requirements.txt 中的flask-security-too>=5.4,<6.0)

下文将按主题逐一展开,每个主题均给出对应的源码或迁移文件依据,便于继续深入研读。

二、认证体系扩展:Basic Auth 与令牌机制

2.1 新增 Basic Auth 支持

3.15.0 为 Faraday API 新增了Basic Auth认证方式。在源码层面,Flask-Login 的request_loader中实现了完整的认证类型分发逻辑,位于 faraday/server/app.py:

@app.login_manager.request_loader def load_user_from_request(request): if app.config['SECURITY_TOKEN_AUTHENTICATION_HEADER'] in flask.request.headers: header = flask.request.headers[app.config['SECURITY_TOKEN_AUTHENTICATION_HEADER']] auth_type, token = None, None try: (auth_type, token) = header.split(None, 1) except ValueError: logger.warning("Authorization header does not have type") flask.abort(401) auth_type = auth_type.lower() if auth_type == 'token': user = verify_token(token) # ... token 校验逻辑 elif auth_type == 'agent': # 由其他 before_request 处理器处理 return None elif auth_type == "basic": username = flask.request.authorization.get('username', '') password = flask.request.authorization.get('password', '') user = User.query.filter_by(username=username).first() if user and user.verify_and_update_password(password): session["last_access"] = time() return user else: logger.warning("Invalid authorization type") flask.abort(401) return None

从这段实现可以看出 3.15.0 之后 API 支持三类Authorization头:

  • token <token>:JWT 风格令牌认证;
  • agent <token>:Agent 令牌认证,专门用于 Agent 场景,由 faraday/server/api/modules/websocket_auth.py 中的require_agent_token在请求前处理器中校验;
  • basic:使用请求头中的username/password字段,查询faraday_user表并调用verify_and_update_password校验,成功后写入session["last_access"]。

此外,faraday/server/utils/web.py 提供了独立的get_basic_auth()工具函数,供服务端内部使用:

def get_basic_auth(): if request.authorization: user, passwd = request.authorization.get('username'), request.authorization.get('password') if (all((user, passwd))): return (user, passwd) return None

该函数在如 faraday/server/commands/ingestelk.py 等场景中被复用(将 ELK 接入配置中的用户名密码封装为basic_auth元组),说明 Basic Auth 不仅面向外部 API 调用,也被服务端内部模块共用。

2.2 websocket_token 支持 GET 方法

websocket_token端点此前仅支持 POST,3.15.0 起同时支持 GET,并明确声明 POST 未来将弃用。实现位于 faraday/server/api/modules/websocket_auth.py:

class WebsocketWorkspaceAuthView(GenericWorkspacedView): route_base = 'websocket_token' schema_class = WebsocketWorkspaceAuthSchema @route('', methods=['GET', 'POST']) def get(self, workspace_name): workspace = get_workspace(workspace_name) signer = TimestampSigner(app.config['SECRET_KEY'], salt="websocket") token = signer.sign(str(workspace.id)).decode('utf-8') return {"token": token}

该端点返回的令牌由TimestampSigner基于服务端SECRET_KEY与websocketsalt 签名生成,用于后续建立 WebSocket 连接时的身份校验。GET 方法加入后,客户端可以直接通过 URL 访问获取令牌,无需构造 POST 请求体,调用方式更简洁。若你的脚本或 Agent 仍在使用 POST 调用该端点,建议尽早迁移到 GET。

2.3 Agent token API 返回续期循环时长

与 Agent 注册相关的agent_token端点新增了令牌轮换周期信息。其实现位于 faraday/server/api/modules/agent_auth_token.py,响应 Schema 定义如下:

class AgentAuthTokenSchema(Schema): token = fields.String(required=True) expires_in = fields.Float(required=True) total_duration = fields.Float(required=True)

端点内部基于 TOTP(RFC 6238)生成动态令牌:

totp = pyotp.TOTP(faraday_server.agent_registration_secret, interval=int( faraday_server.agent_token_expiration)) return AgentAuthTokenSchema().dump( {'token': totp.now(), 'expires_in': totp.interval - datetime.datetime.utcnow().timestamp() % totp.interval, 'total_duration': totp.interval})

响应中的三个字段含义如下:

  • token:当前有效的 TOTP 注册令牌;
  • expires_in:当前令牌距下次轮换的剩余秒数;
  • total_duration:令牌完整的循环周期(秒)。

循环周期由配置项agent_token_expiration控制,默认值为 60 秒(1 分钟),见 faraday/server/config.py。Agent 接入方拿到total_duration后,可以提前计算好令牌轮换节奏,避免因令牌过期导致注册失败。

三、漏洞模型与 API:CVSS / CWE / CVE 列

3.15.0 是 Faraday 漏洞数据模型的一个重要节点:漏洞模型与 API 新增了 CVSS(String)、CWE(String)、CVE(relationship) 三类字段,把漏洞的严重性评分、弱点分类与公开编号统一纳入结构化存储。

3.1 CVSS 字符串字段

在 faraday/server/models.py 中,Vulnerability模型通过 hybrid property 托管 CVSS2 / CVSS3 向量字符串:

# CVSS2 _cvss2_vector_string = Column(Text, nullable=True) @hybrid_property def cvss2_vector_string(self): return self._cvss2_vector_string @cvss2_vector_string.setter def cvss2_vector_string(self, vector_string): self._cvss2_vector_string = vector_string if not self._cvss2_vector_string: self.init_cvss2_attrs() return None try: cvss2 = cvss.CVSS2(vector_string) except Exception as e: logger.error(f"Error parsing CVSS2 vector string: {self._cvss2_vector_string}", e) # CVSS3 结构与之对称,使用 cvss.CVSS3(vector_string) 解析

Setter 在赋值时会调用cvss库对向量字符串做解析校验,解析失败则记录 error 日志而非静默丢弃,保证入库数据格式合法。CVSS4 向量(CVSS4(vector_string))在同文件中亦有对应实现(见 faraday/server/models.py),供后续版本演进使用。

3.2 CVE 关系列

CVE 不再是漏洞上的纯文本标签,而是独立成表并通过多对多关联表连接。相关实现分布在 faraday/server/models.py:

cve_vulnerability_association = db.Table( 'cve_association', Column('vulnerability_id', Integer, db.ForeignKey('vulnerability.id', ondelete='CASCADE'), nullable=False), Column('cve_id', Integer, db.ForeignKey('cve.id'), nullable=False), Index('ix_cve_association_vulnerability_id', 'vulnerability_id'), ) class CVE(db.Model): __tablename__ = 'cve' CVE_PATTERN = r'CVE-\d{4}-\d{4,7}' id = Column(Integer, primary_key=True) name = Column(String(24), unique=True) year = Column(Integer, nullable=True) identifier = Column(Integer, nullable=True) vulnerabilities = relationship("VulnerabilityGeneric", secondary=cve_vulnerability_association)

CVE 模型的构造器会按CVE-YYYY-ID格式自动拆解year与identifier,格式非法时抛出ValueError("Invalid cve format. Should be CVE-YEAR-NUMBERID."):

def __init__(self, name=None, **kwargs): logger.debug(f'cve found {name}') try: name = name.upper() _, year, identifier = name.split("-") super().__init__(name=name, year=year, identifier=identifier, **kwargs) except ValueError as e: logger.error("Invalid cve format. Should be CVE-YEAR-ID.") raise ValueError("Invalid cve format. Should be CVE-YEAR-NUMBERID.") from e

同一漏洞可关联多个 CVE,CVE 也可反向关联多个漏洞(relationship("VulnerabilityGeneric", secondary=cve_vulnerability_association))。CVE 关联表上的索引ix_cve_association_vulnerability_id由迁移 faraday/migrations/versions/51b77832cfde_indexes_to_improve_delete_performance.py 创建,这个迁移同时服务于 CVE 查询性能与下一节所述的工作区删除性能优化。

3.3 CWE 字符串列

CWE(Common Weakness Enumeration,通用弱点枚举)同样独立建表并建立关联。迁移 faraday/migrations/versions/47e53ddc0308_add_cwe.py 创建了cwe表与cwe_vulnerability_association关联表:

op.create_table('cwe', sa.Column('name', sa.Text(), nullable=False), sa.Column('creator_id', sa.Integer(), nullable=True), sa.Column('update_user_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['creator_id'], ['faraday_user.id'], ondelete='SET NULL'), sa.ForeignKeyConstraint(['update_user_id'], ['faraday_user.id'], ondelete='SET NULL'), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('name') ) op.create_table('cwe_vulnerability_association', sa.Column('cwe_id', sa.Integer(), nullable=True), sa.Column('vulnerability_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['cwe_id'], ['cwe.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint(['vulnerability_id'], ['vulnerability.id'], ondelete='CASCADE') )

模型层对应关系定义在 faraday/server/models.py,CWE继承Metadata基类,通过cwe_vulnerability_association与Vulnerability建立多对多关系。CWE 名称唯一约束(UniqueConstraint('name'))保证同一弱点编号不会重复入库。

使用提示:上述 CVSS/CWE/CVE 字段在 3.15.0 起正式进入漏洞 API 的序列化与反序列化流程,漏洞创建、上报(report upload)与检索接口均可直接携带这些字段,例如在 bulk create 的漏洞数据中填入cvss3、cwe、cve等键值,Faraday 会完成解析、建表与关联。

四、工作区删除性能优化

删除工作区是运维中常见的高成本操作——一个包含主机、服务、漏洞、凭证、命令等多张子表数据的实体需要级联清理。3.15.0 从两个层面改进:

  1. 数据库模型级联完善:模型层大量外键显式声明ondelete='CASCADE'(如 faraday/server/models.py、models.py、models.py 等),并在 relationship 上配合passive_deletes=True,让数据库引擎在删除工作区时直接级联删除子记录,而非由 ORM 逐条加载删除。迁移 faraday/migrations/versions/18891ca61db6_add_cascade_delete_from_workspace.py 与该方向一脉相承。
  2. 关键路径加索引:迁移 faraday/migrations/versions/51b77832cfde_indexes_to_improve_delete_performance.py 为高频关联表创建索引(如ix_cve_association_vulnerability_id),显著减少级联删除与后续查询时的全表扫描开销。

该优化对生产环境的直接影响是:在数据量较大的工作区上执行删除操作时,事务锁持有时间更短、数据库负载更低。若你通过faraday manage.py或 API 批量清理测试工作区,升级到包含此变更的版本即可受益。

五、工作区命名约束:禁止正斜杠

工作区名称校验函数位于 faraday/server/api/modules/workspaces.py:

def validate_workspace_name(name): blacklist = ["filter"] if name in blacklist: raise ValidationError(f"Not possible to create workspace of name: {name}") if not re.match(r"^[A-z0-9][A-z0-9_$()+-]{0,250}$", name): raise ValidationError("The workspace name must validate with the regex " "^[a-z0-9][a-z0-9_$()+-]{0,250}$")

关键约束:

  • 首字符必须是字母或数字,整体长度不超过 251 个字符;
  • 后续字符仅允许字母、数字、下划线_、美元符$、括号()、加号+、连字符-;
  • 字符集中不包含正斜杠/,从正则层面杜绝了工作区名被当作 URL 路径段解析时产生的路由歧义;
  • 保留字黑名单["filter"]不允许作为工作区名。

该 Schema 字段通过WorkspaceSchema.name = fields.String(required=True, validate=validate_workspace_name)接入创建/更新工作区的 API 校验链,非法名称会直接返回ValidationError。

六、bulk create 日志改进

批量创建(bulk create)是报告导入的核心路径,负责将扫描器输出解析为 host / service / vulnerability / credential 数据。3.15.0 强化了其日志可观测性,在 faraday/server/api/modules/bulk_create.py 中可以看到清晰的日志埋点:

logger.info("Init bulk create process") # ... logger.debug(f"Needs to create {hosts_to_create} hosts...") # Celery 启用时按消息大小分批投递: logger.info(f"Current size of Message: {_current_size}") logger.debug(f"Appending host {host['ip']}") logger.debug("Sending task to celery") # ... logger.info("No hosts to create")

配合_create_host内部的logger.debug("Trying to create host...")与异常路径的logger.exception("Could not create host %s", ...)(faraday/server/api/modules/bulk_create.py),排查大批量导入失败时可以精确定位到具体主机、消息分片大小与 Celery 任务投递时机,而不再是一段无输出的静默过程。

七、代码质量收敛与依赖升级

3.15.0 同步完成了一批工程化改进,从源码结构可得到验证:

  • 代码风格收敛:减少 flake8 例外配置、统一 Python 3 的super()风格调用,属于纯代码质量变更,不改动对外行为;
  • Flask app 单例化:应用实例从重复创建改为单例模式,服务启动与扩展注册逻辑更可控,相关入口见 faraday/server/app.py;
  • Marshmallow 兼容修复:修复自有 Schema 在 Marshmallow 3.11.0+ 上的兼容问题(FIX Own schema breaking Marshmallow 3.11.0+),保证升级 marshmallow 后 API 序列化层不回归;
  • flask_security_too 升级:UPD flask_security_too to version 4.0.0+,该版本主要引入安全性与兼容性修复。当前仓库主线已进一步将依赖推进到flask-security-too>=5.4,<6.0(见 requirements.txt),表明认证框架持续演进,升级依赖时建议关注该库的迁移说明。

八、总结

Faraday 3.15.0 是一次典型的"能力增强 + 工程收敛"双轨发布:对外,API 新增 Basic Auth 与 GET 版 websocket_token、Agent 令牌携带轮换周期、漏洞模型补齐 CVSS/CWE/CVE 结构化字段,让自动化工具链(Agent、报告导入、第三方脚本)的接入与漏洞治理更顺滑;对内,工作区级联删除提速、bulk create 日志细化、命名约束收紧与代码风格统一,为长期维护和规模化数据管理打下基础。

实践要点回顾:

  • 认证选择:basic/token/agent三类Authorization头并存,按调用方类型选择;
  • 漏洞字段:写入cvss2/cvss3向量字符串时格式需可被cvss库解析,CVE 必须符合CVE-YYYY-ID格式;
  • 工作区命名:避免/、filter及正则不允许的字符,否则 API 返回ValidationError;
  • Agent 令牌:默认 60 秒循环(agent_token_expiration),可依据响应中的total_duration/expires_in规划续期。

若需进一步深入源码细节,建议从 faraday/server/models.py、faraday/server/api/modules/websocket_auth.py、faraday/server/api/modules/bulk_create.py 三个文件入手,它们分别对应数据模型、认证令牌与批量导入三大核心链路。

  • 网络安全
  • 渗透测试
  • 漏洞扫描

【免费下载链接】faraday

Open-source and AI-powered cybersecurity tools for offensive security, vulnerability management, and autonomous pentesting. Built by hackers in Latin America, used worldwide.

项目地址:https://gitcode.com/gh_mirrors/far/faraday
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询