Mastodon
  • 什么是 Mastodon?
  • 使用 Mastodon
    • 注册帐户
    • 设置你的个人资料
    • 在你的账户发布内容
    • 使用网络功能
    • 处理不想看到的内容
    • 推广你和他人
    • 进行偏好设置
    • 更多设置
    • 在站点外使用 Mastodon
    • 迁移或离开账户
    • 运行你自己的站点
  • 运营 Mastodon
    • 准备你的服务器
    • 从源代码安装
    • 配置你的环境
    • 安装可选功能
      • 对象存储
      • 洋葱服务
      • 验证码
      • 单点登录
    • 配置全文搜索
    • 设置你的新实例
    • 使用管理 CLI
    • 升级到新版本
    • 备份你的服务器
    • 迁移到新机器
    • 扩大你的站点规模
    • 审核操作
    • 故障排除
      • 数据库索引损坏
    • 用户组
  • 开发 Mastodon 应用
    • API 入门指南
    • 使用公开数据
    • 获取客户端应用访问权限
    • 使用帐户登录
    • 库与实现
  • 向 Mastodon 项目做贡献
    • 技术概览
    • 设置开发环境
    • 代码结构
    • 路由
    • 漏洞赏金与责任披露
  • 遵循的标准
    • ActivityPub
    • WebFinger
    • 安全性
    • Microformats
    • OAuth
    • Bearcaps
  • REST API
    • Datetime 格式
    • 指南与最佳实践
    • OAuth 令牌
    • OAuth 作用域
    • 速率限制
  • API 方法
    • apps
      • oauth
      • emails
    • accounts
      • bookmarks
      • favourites
      • mutes
      • blocks
      • domain_blocks
      • filters
      • reports
      • follow_requests
      • endorsements
      • featured_tags
      • preferences
      • followed_tags
      • suggestions
      • tags
    • profile
    • statuses
      • media
      • polls
      • scheduled_statuses
    • timelines
      • conversations
      • lists
      • markers
      • streaming
    • grouped notifications
    • notifications
      • push
    • search
    • instance
      • trends
      • directory
      • custom_emojis
      • announcements
    • admin
      • accounts
      • canonical_email_blocks
      • dimensions
      • domain_allows
      • domain_blocks
      • email_domain_blocks
      • ip_blocks
      • measures
      • reports
      • retention
      • trends
    • proofs
    • oembed
  • API 实体
    • Account
    • AccountWarning
    • Admin::Account
    • Admin::CanonicalEmailBlock
    • Admin::Cohort
    • Admin::Dimension
    • Admin::DomainAllow
    • Admin::DomainBlock
    • Admin::EmailDomainBlock
    • Admin::Ip
    • Admin::IpBlock
    • Admin::Measure
    • Admin::Report
    • Announcement
    • Appeal
    • Application
    • Context
    • Conversation
    • CustomEmoji
    • DomainBlock
    • Error
    • ExtendedDescription
    • FamiliarFollowers
    • FeaturedTag
    • Filter
    • FilterKeyword
    • FilterResult
    • FilterStatus
    • IdentityProof
    • Instance
    • List
    • Marker
    • MediaAttachment
    • Notification
    • NotificationPolicy
    • NotificationRequest
    • Poll
    • Preferences
    • PreviewCard
    • PreviewCardAuthor
    • PrivacyPolicy
    • Reaction
    • Relationship
    • RelationshipSeveranceEvent
    • Report
    • Role
    • Rule
    • ScheduledStatus
    • Search
    • Status
    • StatusEdit
    • StatusSource
    • Suggestion
    • Tag
    • TermsOfService
    • Token
    • Translation
    • V1::Filter
    • V1::Instance
    • V1::NotificationPolicy
    • WebPushSubscription

安全性

基于 HTTP 和 JSON-LD 的公钥加密与支持的签名方案。

    • HTTP 签名
      • 创建 HTTP 签名
      • 验证 HTTP 签名
    • 关联数据签名
      • 创建 LD 签名
      • 验证 LD 签名

HTTP 签名

app/lib/request.rb

HTTP 签名 是一项通过在 HTTP 请求中使用 Signature: 标头来签署 HTTP 消息的规范。为了验证接收到的任何活动是否由生成该活动的行为体所创作,Mastodon 要求使用 HTTP 签名。启用安全模式后,所有 GET 请求也需要 HTTP 签名。

对于任何传入 Mastodon 的 HTTP 请求,都应附加 Signature 头:

Signature: keyId="https://my.example.com/actor#main-key",headers="(request-target) host date",signature="Y2FiYW...IxNGRiZDk4ZA=="

Signature: 头的三个部分可以分解如下:

Signature:
  keyId="https://my.example.com/actor#main-key",
  headers="(request-target) host date",
  signature="Y2FiYW...IxNGRiZDk4ZA=="

keyId 应与行为体和用于生成 signature 的密钥相对应,signature 的值等于 headers 中的所有参数连接在一起并由密钥签名,然后进行 Base64 编码后得到的值。有关行为体密钥的更多信息,请查看 ActivityPub > 公钥。一个示例密钥如下所示:

"publicKey": {
    "id": "https://my.example.com/actor#main-key",
    "owner": "https://my.example.com/actor",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXc4vkECU2/CeuSo1wtn\nFoim94Ne1jBMYxTZ9wm2YTdJq1oiZKif06I2fOqDzY/4q/S9uccrE9Bkajv1dnkO\nVm31QjWlhVpSKynVxEWjVBO5Ienue8gND0xvHIuXf87o61poqjEoepvsQFElA5ym\novljWGSA/jpj7ozygUZhCXtaS2W5AD5tnBQUpcO0lhItYPYTjnmzcc4y2NbJV8hz\n2s2G8qKv8fyimE23gY1XrPJg+cRF+g4PqFXujjlJ7MihD9oqtLGxbu7o1cifTn3x\nBfIdPythWu5b4cujNsB3m3awJjVmx+MHQ9SugkSIYXV0Ina77cTNS0M2PYiH1PFR\nTwIDAQAB\n-----END PUBLIC KEY-----\n"
 },

另请查看:https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/

创建 HTTP 签名

要创建 HTTP 签名,你必须定义要执行哈希和签名的标头。例如,考虑以下 GET 请求:

GET /users/username/outbox HTTP/1.1
Host: mastodon.example
Date: 18 Dec 2019 10:08:46 GMT
Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"

签名字符串使用 headers 中定义的 HTTP 标头的值构建,并用换行符连接。通常,你希望包括请求目标,以及主机和日期。如果没有提供 Date: 标头,Mastodon 会进行假定。对于上面的 GET 请求,为了使用 headers="(request-target) host date" 生成 Signature:,我们将生成以下字符串:

(request-target): get /users/username/outbox
host: mastodon.example
date: 18 Dec 2019 10:08:46 GMT

请注意,我们不关心 Accept: 标头,因为我们不会在 headers 中指定它。

然后,使用 RSA-SHA256(使用 SHA-256 的 RSASSA-PKCS1-v1_5)对签名字符串执行哈希处理,并使用行为体的私钥进行签名。结果作为 signature 附加在 Signature: 头中。最终的请求如下所示:

GET /users/username/inbox HTTP/1.1
Host: mastodon.example
Date: 18 Dec 2019 10:08:46 GMT
Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"
Signature: keyId="https://my.example.com/actor#main-key",headers="(request-target) host date",signature="Y2FiYW...IxNGRiZDk4ZA=="

此请求在功能上等同于说 https://my.example.com/actor 正在请求 https://mastodon.example/users/username/inbox,并通过使用链接到 keyId 的私钥对 (request-target)、Host: 和 Date: 进行签名来证明他们发送了此请求,从而生成提供的 signature。

签名 POST 请求和摘要标头

在向 Mastodon 发出 POST 请求时,你必须计算请求正文的 RSA-SHA256 摘要哈希,并将此哈希(以 base64 编码)包含在 Digest: 标头中。Digest: 标头也必须包含在 Signature: 标头的 headers 参数中。例如:

POST /users/username/inbox HTTP/1.1
HOST: mastodon.example
Date: 18 Dec 2019 10:08:46 GMT
Digest: sha-256=hcK0GZB1BM4R0eenYrj9clYBuyXs/lemt5iWRYmIX0A=
Signature: keyId="https://my.example.com/actor#main-key",headers="(request-target) host date digest",signature="Y2FiYW...IxNGRiZDk4ZA=="
Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "actor": "https://my.example.com/actor",
  "type": "Create",
  "object": {
    "type": "Note",
    "content": "Hello!"
  },
  "to": "https://mastodon.example/users/username"
}

验证 HTTP 签名

app/controllers/concerns/signature_verification.rb

考虑以下请求:

POST /users/username/inbox HTTP/1.1
Host: mastodon.example
Date: 18 Dec 2019 10:08:46 GMT
Digest: e37e179c75071a291f90a5fd4f848da87b491f1282f7bb8509ef2115b81ee0f4
Signature: keyId="https://my.example.com/actor#main-key",headers="(request-target) host date digest",signature="Y2FiYW...IxNGRiZDk4ZA=="
Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "actor": "https://my.example.com/actor",
  "type": "Create",
  "object": {
    "type": "Note",
    "content": "Hello!"
  }
  "to": "https://mastodon.example/users/username"
}

Mastodon 使用以下算法验证签名:

  • 将 Signature: 分解为单独的参数。
  • 从 headers 的值构造签名字符串。
  • 获取 keyId 并解析为行为体的 publicKey。
  • 对签名字符串执行 RSA-SHA256 哈希处理,并将其与用 publicKey[publicKeyPem] 解密的 Base64 解码后的 signature 进行比较。
  • 使用 Date: 标头检查已签名的请求是否在过去 12 小时内发出。

关联数据签名

app/lib/activitypub/linked_data_signature.rb
由于在草案阶段和规范最终确定阶段之间 JSON-LD @context 发生了更改,Mastodon 当前的 LD 签名实现已过时。Mastodon 期望 type 为 RsaSignature2017,而后来的草案通过命名空间 https://w3id.org/security/v2 定义了 RsaSignature2018。此外,整个 LD 签名规范已被 可验证凭据完整性规范 1.0 取代,该规范与早期 LD 签名规范在很大程度上不兼容。因此,不建议实现对 LD 签名的支持。

关联数据签名 1.0 是一项将加密签名附加到 JSON-LD 文档的草案规范。LD 签名在 Mastodon 中使用不广泛,但在以下情况下使用:

  • 运行 自毁 序列以将 Delete 活动发送到所有已知联合实例时,有效负载将使用 LD 签名,因为 HTTP 签名将不可用。接收服务器将通过针对本地缓存的行为体密钥验证签名来处理签名,因为 HTTP 服务器将不再托管旧的行为体信息。
  • 接受来自中继的活动时。公共活动可以选择使用 LD 进行签名并发送给中继,这样任何订阅中继的服务器都不必手动从源重新获取活动。这可以防止潜在的无限多服务器尝试从你的实例加载嘟文。

创建 LD 签名

要创建签名,Mastodon 使用附加到位于 https://mastodon.example/users/username#main-key 的行为体的密钥对。然后,它创建文档的 RSA-SHA256 哈希,使用密钥对对其进行签名,并对生成的输出进行 Base64 严格编码以派生 signatureValue。以下哈希将被合并到 JSON-LD 文档中:

"signature": {
    "type": "RsaSignature2017",
    "creator": "https://mastodon.example/users/username#main-key",
    "created": "2019-12-08T03:48:33.901Z",
    "signatureValue": "s69F3mfddd99dGjmvjdjjs81e12jn121Gkm1"
}

验证 LD 签名

要验证签名,Mastodon 使用以下算法:

  • 确保 signature 存在且为哈希。
  • 确保 signature[type] 为 RsaSignature2017。
  • 获取 signature[creator] URI。确保创建者存在。
  • 从 signature 中剥离 type、id 和 signatureValue,只留下 signature[creator] 和 signature[created]。
  • 对 signatureValue 进行 Base64 解码,并根据 signature[creator] 中的公钥对其进行验证。

翻译状态: 本文是英文页面 Security 的翻译,最后翻译时间:2025-04-21,点击这里可以查看翻译后页面的改动。

最后更新于 April 21, 2025 · 改进此页面
也可在此找到: English

赞助商

Dotcom-Monitor LoadView Stephen Tures Swayable SponsorMotion

加入Mastodon · 博客 ·

查看源代码 · CC BY-SA 4.0 · 版权信息