Graphql-ruby habtm 中的范围界定,嵌套查询中的数据泄漏
Graphql-ruby scoping in habtm, data leak in nested query
这是使用标准 graphql-ruby 设置时发生的数据泄漏示例。
使用下面的 graphql 嵌套请求,响应 returns 数据嵌套在公司 1 下,属于公司 2。我希望响应仅限于属于公司的会计师日志嵌套在.
就是这样,这是在泄露信息。
问题是我们如何修补漏洞,以便响应中返回的唯一数据及其嵌套对象是属于公司的数据(根对象)。
这个查询:
query {
company(id: "1") {
id
name
activityLog {
id
activityAt
accountant {
id
name
}
companyId
}
accountants {
id
name
activityLog {
id
activityAt
companyId
}
}
}
}
returns 此回复:
{
"data": {
"company": {
"id": "1",
"name": "AwsomeCo",
"activityLog": [
{
"id": "1",
"activityAt": "2019-10-12 16:40:13 UTC",
"accountant": {
"id": "100",
"name": "Mr Smith",
},
"companyId": "1"
}
],
"accountants": [
{
"id": "100",
"name": "Mr Smith"
"activityLog": [
{
"id": "1",
"activityAt": "2019-10-12 16:40:13 UTC",
"companyId": "1"
},
{
"id": "2",
"activityAt": "2019-10-11 16:40:13 UTC",
"companyId": "2" // OTHER COMPANY, NEED TO PRESERVE PARENT SCOPE
},
],
}
}
}
}
}
在公司 1 的嵌套元素中泄漏公司 2 的事务日志数据。
同样,问题是:我们如何保留范围,仅在所显示的公司上下文中显示数据?
重现代码:
GraphQL 类型(使用 graphql-ruby gem)
#query_type.rb
module Types
class QueryType < Types::BaseObject
# Add root-level fields here.
# They will be entry points for queries on your schema.
field :company_leak, Types::ExampleLeak::CompanyType, null: false do
argument :id, ID, required: true
end
field :companies_leak, [ Types::ExampleLeak::CompanyType ], null: false
def company_leak(id: )
Company.find(id)
end
def companies_leak
Company.all
end
end
end
module Types
module ExampleLeak
class CompanyType < BaseObject
field :id, ID, null: false
field :name, String, null: false
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
field :accountants, [Types::ExampleLeak::AccountantType], null: true
end
end
end
module Types
module ExampleLeak
class AccountantType < BaseObject
field :id, ID, null: false
field :name, String, null: false
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
field :companies, [Types::ExampleLeak::CompanyType], null: true
end
end
end
module Types
module ExampleLeak
class TransactionLogType < BaseObject
field :id, ID, null: false
field :activity_at, String, null: false
field :company_id, ID, null: false
field :accountant, Types::ExampleLeak::AccountantType, null: false
end
end
end
型号
class Company < ApplicationRecord
has_and_belongs_to_many :accountants
has_many :transaction_logs
end
class Accountant < ApplicationRecord
has_and_belongs_to_many :companies
has_many :transaction_logs
end
class TransactionLog < ApplicationRecord
belongs_to :company
belongs_to :accountant
end
seeds.rb
awesomeco = Company.create!(name: 'AwesomeCo')
boringco = Company.create!(name: 'BoringCo')
mr_smith = Accountant.create!(name: "Mr. Smith")
awesomeco.accountants << mr_smith
boringco.accountants << mr_smith
mr_smith.transaction_logs.create!(company: awesomeco, activity_at: 1.day.ago)
mr_smith.transaction_logs.create!(company: boringco, activity_at: 2.days.ago)
Public 包含完整代码的 repo,用作教育资源:
我们可以按如下方式更新 class AccountantType < BaseObject
中的字段来解析事务日志:
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true,
resolve: ->(obj, args, ctx) {
company_leak = ctx.irep_node.parent.parent.arguments[:id]
companies_leak = ctx.parent.parent.object.object.id
TransactionLog.where(id: company_leak.present? ? company_leak : companies_leak)
}
如果给公司 ID 一个参数,它将根据该 ID 获取事务日志,否则根据其父 Accountant
听起来像是 Pundit 和范围界定的完美用例。这样一来,如果用户验证了他们的查询,就会自动确定正确的公司范围
这是使用标准 graphql-ruby 设置时发生的数据泄漏示例。
使用下面的 graphql 嵌套请求,响应 returns 数据嵌套在公司 1 下,属于公司 2。我希望响应仅限于属于公司的会计师日志嵌套在.
就是这样,这是在泄露信息。
问题是我们如何修补漏洞,以便响应中返回的唯一数据及其嵌套对象是属于公司的数据(根对象)。
这个查询:
query {
company(id: "1") {
id
name
activityLog {
id
activityAt
accountant {
id
name
}
companyId
}
accountants {
id
name
activityLog {
id
activityAt
companyId
}
}
}
}
returns 此回复:
{
"data": {
"company": {
"id": "1",
"name": "AwsomeCo",
"activityLog": [
{
"id": "1",
"activityAt": "2019-10-12 16:40:13 UTC",
"accountant": {
"id": "100",
"name": "Mr Smith",
},
"companyId": "1"
}
],
"accountants": [
{
"id": "100",
"name": "Mr Smith"
"activityLog": [
{
"id": "1",
"activityAt": "2019-10-12 16:40:13 UTC",
"companyId": "1"
},
{
"id": "2",
"activityAt": "2019-10-11 16:40:13 UTC",
"companyId": "2" // OTHER COMPANY, NEED TO PRESERVE PARENT SCOPE
},
],
}
}
}
}
}
在公司 1 的嵌套元素中泄漏公司 2 的事务日志数据。
同样,问题是:我们如何保留范围,仅在所显示的公司上下文中显示数据?
重现代码:
GraphQL 类型(使用 graphql-ruby gem)
#query_type.rb
module Types
class QueryType < Types::BaseObject
# Add root-level fields here.
# They will be entry points for queries on your schema.
field :company_leak, Types::ExampleLeak::CompanyType, null: false do
argument :id, ID, required: true
end
field :companies_leak, [ Types::ExampleLeak::CompanyType ], null: false
def company_leak(id: )
Company.find(id)
end
def companies_leak
Company.all
end
end
end
module Types
module ExampleLeak
class CompanyType < BaseObject
field :id, ID, null: false
field :name, String, null: false
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
field :accountants, [Types::ExampleLeak::AccountantType], null: true
end
end
end
module Types
module ExampleLeak
class AccountantType < BaseObject
field :id, ID, null: false
field :name, String, null: false
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true
field :companies, [Types::ExampleLeak::CompanyType], null: true
end
end
end
module Types
module ExampleLeak
class TransactionLogType < BaseObject
field :id, ID, null: false
field :activity_at, String, null: false
field :company_id, ID, null: false
field :accountant, Types::ExampleLeak::AccountantType, null: false
end
end
end
型号
class Company < ApplicationRecord
has_and_belongs_to_many :accountants
has_many :transaction_logs
end
class Accountant < ApplicationRecord
has_and_belongs_to_many :companies
has_many :transaction_logs
end
class TransactionLog < ApplicationRecord
belongs_to :company
belongs_to :accountant
end
seeds.rb
awesomeco = Company.create!(name: 'AwesomeCo')
boringco = Company.create!(name: 'BoringCo')
mr_smith = Accountant.create!(name: "Mr. Smith")
awesomeco.accountants << mr_smith
boringco.accountants << mr_smith
mr_smith.transaction_logs.create!(company: awesomeco, activity_at: 1.day.ago)
mr_smith.transaction_logs.create!(company: boringco, activity_at: 2.days.ago)
Public 包含完整代码的 repo,用作教育资源:
我们可以按如下方式更新 class AccountantType < BaseObject
中的字段来解析事务日志:
field :transaction_logs, [Types::ExampleLeak::TransactionLogType], null: true,
resolve: ->(obj, args, ctx) {
company_leak = ctx.irep_node.parent.parent.arguments[:id]
companies_leak = ctx.parent.parent.object.object.id
TransactionLog.where(id: company_leak.present? ? company_leak : companies_leak)
}
如果给公司 ID 一个参数,它将根据该 ID 获取事务日志,否则根据其父 Accountant
听起来像是 Pundit 和范围界定的完美用例。这样一来,如果用户验证了他们的查询,就会自动确定正确的公司范围