- 网络安全
- 渗透测试
- 漏洞扫描
【免费下载链接】faraday
Open-source and AI-powered cybersecurity tools for offensive security, vulnerability management, and autonomous pentesting. Built by hackers in Latin America, used worldwide.
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 从两个层面改进:
- 数据库模型级联完善:模型层大量外键显式声明
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 与该方向一脉相承。 - 关键路径加索引:迁移 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.
相关推荐
Faraday 3.19.0 版本能力详解:Bulk 批量接口、CVSS 漏洞模型与运维加固
Faraday 3.19.0 版本能力详解:Bulk 批量接口、CVSS 漏洞模型与运维加固 本篇围绕 Faraday v3.19.0 版本的变更清单展开,逐条
网络安全渗透测试漏洞扫描Faraday 4.1.0 版本技术解析:API 过滤、CVSS/CWE 建模与 Agent 标签能力的增强
Faraday 4.1.0 版本技术解析:API 过滤、CVSS/CWE 建模与 Agent 标签能力的增强 本篇技术指南以 Faraday 官方变更日志( C
网络安全渗透测试漏洞扫描Faraday 4.0.4 版本解析:多工作区 Agent 架构、排序修复与漏洞查询性能优化
Faraday 4.0.4 版本解析:多工作区 Agent 架构、排序修复与漏洞查询性能优化 本篇文章围绕 Faraday 开源项目 4.0.4 版本(2022
网络安全渗透测试漏洞扫描
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考