Receber por email
← Voltar para o catálogo

spree-security

Secure a Spree deployment — Rails credentials and env-var hygiene, Devise auth (Spree v5 ships it in-core; `spree_auth_devise` is archived), CanCanCan authorization rules, Doorkeeper OAuth2 scopes, Storefront publishable key vs admin API key, webhook HMAC verification, OWASP Top 10 for Rails (mass assignment, CSRF, SQL injection via Ransack, XSS, IDOR through prefixed IDs), PCI scope (Spree never

34estrelas
Atualizado há 5 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add OrcaQubits/agentic-commerce-skills-plugins

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/spree-security/svg)](https://www.skillteca.com.br/skills/spree-security)

Skills relacionadas

Ver todas de DevOps e Infra →

Alerta por categoria

Receba novas skills de DevOps e Infra toda segunda

1 email curto, só com as skills novas de DevOps e Infra. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Spree Security

Before writing code

Fetch live docs:

  1. Check https://github.com/spree/spree/security for the security policy and known advisories.
  2. Cross-reference https://rubysec.com for Rails / Ruby gem CVEs.
  3. Inspect Spree::Ability (CanCanCan) in the live source for current default permissions.
  4. Verify auth config in config/initializers/devise.rb.
  5. For OAuth2, check Doorkeeper config in config/initializers/doorkeeper.rb.

Conceptual Architecture

Auth Stack

| Layer | Tool | |-------|------| | Customer authentication | Devise (v5 ships in-core; spree_auth_devise is archived) | | Admin authentication | Same Devise system; differentiation via Spree::Role | | Authorization | CanCanCan via Spree::Ability | | API auth (v3 Store) | Publishable key + per-user JWT | | API auth (v3 Admin) | Per-user API key + OAuth2 (Doorkeeper) | | API auth (v2 legacy) | OAuth2 (Doorkeeper) password + client_credentials grants | | OAuth2 server | Doorkeeper | | CSRF | Rails default — required for HTML, exempted for API |

spree_auth_devise Is Deprecated

The standalone spree_auth_devise gem is archived as of Feb 2026. Spree v5+ ships Devise auth in the core gem. Do NOT install the old gem on new projects — it conflicts and creates a maintenance burden.

CanCanCan Permission Model

# app/models/spree/ability.rb
class Spree::Ability
  include CanCan::Ability

  def initialize(user)
    user ||= Spree.user_class.new
    if user.has_spree_role?(:admin)
      can :manage, :all
    elsif user.has_spree_role?(:order_manager)
      can :manage, Spree::Order
    else
      can :read, [Spree::Product, Spree::Taxon]
    end
  end
end

Extend via decorator — don't replace.

API Auth Tiers (v3)

| Token type | Scope | Where stored | |------------|-------|--------------| | Publishable key (pk_…) | Read-only public catalog + cart endpoints | Browser env (NEXT_PUBLIC_*) — safe | | User JWT | Customer's account, their orders | httpOnly cookie server-side | | Cart token (order_token) | Anonymous cart only | httpOnly cookie server-side | | Admin API key | Per-user admin scope | Server env vars or vault — never to browser | | OAuth2 access token (admin scope) | App integration | Server-to-server only |

Webhook HMAC Verification

Webhooks 2.0 signs with HMAC-SHA256 over the raw body using a per-endpoint shared secret. Always verify:

def verify(body, header, secret)
  expected = OpenSSL::HMAC.hexdigest('SHA256', secret, body)
  ActiveSupport::SecurityUtils.secure_compare(expected, header.sub(/^sha256=/, ''))
end

Use secure_compare — never == (timing attack).

Rails OWASP Checklist for Spree

| Risk | Spree-specific mitigation | |------|---------------------------| | A01 Broken access control | CanCanCan Spree::Ability — never skip authorize!. Multi-store scoping. | | A02 Cryptographic failures | Rails credentials. TLS everywhere. No secrets in YAML. | | A03 Injection | ActiveRecord parameterization. Ransack: lock ransackable_attributes. | | A04 Insecure design | Don't accept user-supplied IDs without ownership check. Use prefixed IDs. | | A05 Misconfiguration | config.force_ssl = true. config.action_controller.default_url_options = { protocol: 'https' }. | | A06 Vulnerable deps | bundler-audit, brakeman in CI. | | A07 ID&A failures | Devise default rate-limits. Add 2FA via devise-two-factor. | | A08 Software integrity | Pin gem versions. Verify gem signatures where supported. | | A09 Logging | Filter params: Rails.application.config.filter_parameters += [:password, :credit_card]. | | A10 SSRF | Never Net::HTTP.get(params[:url]). |

Ransack Filter Exposure

API v2 filters use Ransack (filter[status_eq]=complete). By default, all columns and associations are filterable. Lock down per-model:

# app/models/spree/order_decorator.rb
module SecureOrderRansack
  def self.prepended(base)
    base.class_eval do
      def self.ransackable_attributes(_auth = nil)
        %w[number state payment_state shipment_state created_at]
      end

      def self.ransackable_associations(_auth = nil)
        %w[user line_items]
      end
    end
  end
end
Spree::Order.prepend(SecureOrderRansack)

Without this, attackers can filter by sensitive columns (passwords, tokens).

Prefixed IDs (v3)

API v3's prefixed IDs (prod_…, ord_…) are opaque strings — they don't expose row counts (sequential integers do). But always pair with ownership checks:

order = current_store.orders.find(params[:id])  # scoped lookup

Not:

order = Spree::Order.find(params[:id])  # IDOR risk

PCI Scope

Spree's never touches raw card numbers when configured correctly:

  • Stripe Elements / Adyen Drop-in / PayPal Buttons collect card data in the gateway's iframe
  • Spree stores only the gateway's token (tok_…, pm_…, etc.)
  • This keeps the merchant in SAQ-A scope, the lightest PCI tier

Don't build a custom card form that sends params[:card_number] to Rails. That escalates PCI scope dramatically.

Multi-Store Data Isolation

As covered in spree-multi-store, always scope queries by current_store. A single missed scope can leak another tenant's orders.

Devise Password Policies

Configure in config/initializers/devise.rb:

config.password_length = 12..128
config.maximum_attempts = 5
config.unlock_in = 30.minutes
config.timeout_in = 30.minutes

Add zxcvbn-style strength via devise_zxcvbn if needed.

2FA

Spree doesn't ship 2FA, but Devise extensions add it:

gem 'devise-two-factor'

Or use WebAuthn (webauthn-ruby) for hardware-key auth on admin accounts.

Rails Master Key Hygiene

  • RAILS_MASTER_KEY unlocks config/credentials.yml.enc
  • Store it in your platform's secret manager (Heroku config, AWS Secrets Manager, etc.)
  • Never commit config/master.key — gitignore it
  • Rotate periodically: re-encrypt credentials with a new key, update env

CSRF Exemption for APIs

class Spree::Api::V3::BaseController < ActionController::API
  # ActionController::API doesn't include CSRF protection — correct for APIs
end

But never disable CSRF on HTML controllers (admin UI). Default Rails CSRF tokens protect admin from cross-origin attacks.

Rate Limiting

Spree's per-endpoint API rate limiting is built in (v5+). For brute-force protection on admin login, layer rack-attack:

# config/initializers/rack_attack.rb
Rack::Attack.throttle('admin_login', limit: 5, period: 15.minutes) do |req|
  req.ip if req.path == '/admin/login' && req.post?
end

Implementation Guidance

Pre-Production Security Checklist

  1. config.force_ssl = true + HSTS headers
  2. RAILS_MASTER_KEY in vault (not in code)
  3. Devise password policy raised from defaults
  4. CanCanCan abilities reviewed; no can :manage, :all outside admin role
  5. Ransack ransackable_attributes locked per exposed model
  6. bundler-audit and brakeman clean in CI
  7. Webhook signature verification on every receiver
  8. OAuth2 application secrets rotated quarterly
  9. API key issuance auditable — Spree stores them; track in logs
  10. Multi-store scope test — assert customer can't fetch other stores' orders
  11. PCI scope verified — gateway iframes only; never custom card form
  12. Admin 2FA for all admin users
  13. config.filter_parameters includes password, token, secret, credit_card
  14. CSP headers for the storefront (Content-Security-Policy)
  15. Backup encryption at rest
  16. Image upload validation — limit MIME types, sizes; scan for ImageMagick CVEs

Brakeman in CI

- run: bundle exec brakeman -q --no-pager --exit-on-warn

Treat new findings as build failures.

Bundler-Audit

bundle exec bundler-audit c
Compartilhar X LinkedIn