Spreeのドキュメントを日本語に訳しました。意訳や怪しい部分もあるのでおかしなところがあればご指摘ください。
SECURITY - DEVELOPER GUIDE | SPREE COMMERCE
概要
適切なアプリケーションデザイン、聡明なプログラミング、そして安全なインフラストラクチャーはあらゆる安全なEコマースサイトを作るうえで欠かせないものとなっています。Spreeチームは安全で有益なウェブプレゼンスをあなたに与えられるよう最大限の努力をしていますが、それらのツールを適切に使い、配置できるかは貴方次第です。Rails Security Guideを読み、理解することを強くおすすめします。
セキュリティ上の問題を報告する場合
セキュリティ面の脆弱性は、公にアナウンスしないでください。専用のメールアドレスがあります。我々は素早くそれらの問題の重要度を決定し、適切なバージョンにて修正します。我々はあなたの発見を評価し、ブログ記事に記名させていただきます。
もし修正パッチをあなた自身で提供いただける場合、__セキュリティ面の問題はプルリクエストを作らないでください。__代わりにあなたのフォークにコミットし、下記のコマンドを実行してください。
$ git format-patch HEAD~1..HEAD --stdout > patch.txt
このコマンドはpatch.txt
というファイルを生成します。その後にパッチを説明とともに我々の専用メールアドレスへ送信してください。
認証
もしspree_auth_devise
をアプリケーションのセットアップとともにインストールしたならば、サードパーティー製の認証用ライブラリでよく知られているDeviseを使用することとなります。このライブラリは便利な機能を提供しており、Spree内で以下のような機能を提供します。
- 認証
- 強固なパスワード暗号化(暗号化アルゴリズムの指定も可)
- "Remember Me"機能(クッキーによるオートログイン)
- "Forget my password"機能(メールアドレスによるパスワード再設定)
- トークンベースアクセス(REST API機能)
Deviseの設定
Spreeをインストールするとspree_auth_deviseも一緒に含まれており、DeviseによるSpreeの認証機能が提供されています。当ガイドのこのセクションではデフォルトのセットアップについて説明します。もし独自の認証を使うならその認証エンジンのマニュアルを参考にしてください。
私達はSpreeサイトの認証に必要な機能だけを扱えるよう変更したDeviseを使っています。下記がデフォルトで使用できる設定です。
- パスワードをソルトとともに暗号化してデータベースに保存する
- データベースクエリによるユーザー認証
- ユーザー登録後、すぐに使用可能にする(メールアドレス認証は行わない)
- ログイン維持とパスワード再設定ツールが有効化されている
この構成は、代表的なEコマースサイトの合理的な出発地点となります。Deviseは様々な構成を設定することができますが、それはこのドキュメントの範囲を超えています。さらなる詳細を求める開発者の方は、Devise Wikiをご覧いただくことをおすすめします。
REST API
REST APIの振る舞いは、通常のユーザーと少し異なります。第一に管理者は他のユーザーがREST APIを使用する前にアクセスキーを生成しなければなりません。鍵生成をしなければいけないのは管理者自身も含みます。しかしSpree::Api::Config[:requires_authentication]
がfalse
に設定されている場合にはこの限りではありません。
Spree::Api::Config[:requires_authentication]
がfalse
にセットされている場合には、参照のみのAPIリクエストは全てのユーザーが可能です。Spree内のデータを更新する場合にはAPIキーが必要となり、ユーザー自身がそれらのレコードを変更する権限を持っていることが必要となります。
鍵の取り扱いについてはあなた次第です。追加対策として、この認証はREST APIによるセッションやクッキーが生成されていないリクエストの度に行わねばなりません。
権限
Spreeは、権限の設定のためにCanCanという素晴らしいgemを使用しています。もしあなたがこれに詳しくないのならRyan Batesの素晴らしいscreencastを見るべきです。CanCanの詳しい説明はこのガイドの範囲ではありません。
デフォルトルール
下記のSpreeのコードはability.rb
から抜粋したもので、デフォルトの権限ルールについての洞察を提供しています。
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
can :manage, :all
else
#############################
can [:read,:update,:destroy], Spree.user_class, :id => user.id
can :create, Spree.user_class
#############################
can :read, Order do |order, token|
order.user == user || order.token && token == order.token
end
can :update, Order do |order, token|
order.user == user || order.token && token == order.token
end
can :create, Order
can :read, Address do |address|
address.user == user
end
#############################
can :read, Product
can :index, Product
#############################
can :read, Taxon
can :index, Taxon
#############################
end
上記のルールは、以下の実際的なルールをSpreeユーザーに付与しています。
- Admin権限は全てにアクセスできる(他のルールは無視されます)
- 誰でも
User
を作成でき、そのアカウントのユーザーだけがそのユーザー情報を読み書きできる。 - 誰でも
Order
を作成でき、その注文のユーザーだけが注文情報を読み書きできる。 - 誰でもproductページを閲覧でき、検索を含む
Products
リストを閲覧できる。 - 誰もが
Taxons
のリストを閲覧できる。
ルールの適用
CanCanは、それを尋ねられたときにのみ権限の適用が可能となります。言い換えるなら、もしソースコードが権限チェックをしていなければ、権限ベースのアクセス拒否をする方法はないということです。一般的には、Railsのコントローラに適切なコードを付与することで扱われています。より詳しい情報はCanCan Wikiを見てください。
権限ルールのカスタマイズ
我々は、エクステンション開発者とそのユーザーが権限をより簡単にカスタマイズできるよう、オリジナルのCanCanのコンセプトを少々変更しました。例えば"artwork extension"によりユーザーが注文に大して独自のartworkを不可できるようにするためには、彼らがその権限を所持できるようルールを追加する必要があります。
カスタム権限のコツは、エクステンションにAbilityDecorator
を追加し、必要な権限を登録することです。下記のコードは、オーナーのみがartworkを更新閲覧できるようアクセスを制限する例です。
class AbilityDecorator
include CanCan::Ability
def initialize(user)
can :read, Artwork do |artwork|
artwork.order && artwork.order.user == user
end
can :update, Artwork do |artwork|
artwork.order && artwork.order.user == user
end
end
end
Spree::Ability.register_ability(AbilityDecorator)
Admin NameSpace内におけるカスタムロール
もしSpreeの管理者パネルにアクセスするカスタムロールを考えているならば、心にとめておくべき検討事項があります。
Spreeは管理者パネルを認可するのに、2つのCanCanの認証コマンドを用いています。:admin
と認可するアクションの名前です。もしあなたが管理者パネルにアクセスできるカスタムロールを必要としているなら、そのロールは:admin
と、適切なリソースのアクションの両方へのアクセスロールをcan
しなければなりません。例えば、もし販売担当者がAdmin Orderパネルにアクセス可能だがそれ以外の管理者エリアにアクセスできないようにするなら、AbilityDecorator
を下記のようにする必要があります。
class AbilityDecorator
include CanCan::Ability
def initialize(user)
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('sales_rep')
can [:admin, :index, :show], Spree::Order
end
end
end
Spree::Ability.register_ability(AbilityDecorator)
以下のコード、SpreeのAdmin::BaseController
はAdminエリアのコントローラ全てに継承され適用されます。
def authorize_admin
if respond_to?(:model_class, true) && model_class
record = model_class
else
record = Object
end
authorize! :admin, record
authorize! action, record
end
もしAdminエリア内に独自のモデルのコントローラを作る必要がある場合、コントローラ内にmodel_class
メソッドを使い、操作するモデルを手動で指定する必要があるでしょう。
module Spree
module Admin
class WidgetsController < BaseController
def index
# Relevant code in here
end
private
def model_class
Widget
end
end
end
end
これは、CanCanがデフォルトではAdminエリアにあるオーソライズコントローラを見つけることができないために必要です。model_class
で指定することにより、SpreeはCanCanにオーソライズコントローラを使うよう伝えることができます。
Tokenized Permissions
アクセスのために認証を要求することなく、特定のリソースへアクセスできることが望ましい状況も存在します。
Spreeはいわゆる「ゲストチェックアウト」を許可しておりユーザーはメールアドレスのみを提供し、アカウントを作ることを要求しません。この場合、オリジナルの顧客だけが見ることのできる注文へのアクセスを制限したいはずです。その方法として、"tokenized"URLを使います。
http://example.com/orders?token=aidik313dsfs49d
SpreeはTokenizedPermission
モデルを提供し、安全なトークンを使い様々なリソースへのアクセスを許可しています。このモデルはSpree::TokenResource
モジュールと連携して動作します。
module Spree
module Core
module TokenResource
module ClassMethods
def token_resource
has_one :tokenized_permission, :as => :permissable
delegate :token, :to => :tokenized_permission, :allow_nil => true
after_create :create_token
end
end
def create_token
permission = build_tokenized_permission
permission.token = token = ::SecureRandom::hex(8)
permission.save!
token
end
def self.included(receiver)
receiver.extend ClassMethods
end
end
end
end
ActiveRecord::Base.class_eval { include Spree::Core::TokenResource }
Orderモデルは、このインターフェースが既に使われているSpreeモデルのひとつです。下記のコードスニペットはどのようにこれを使用すればよいか表しています。
Spree::Order.class_eval do
token_resource
end
もしデフォルトのCanCanがOrderに対し与えている権限を調べたいなら、認証されていないユーザーがどのようにアクセスを許されているかを見てください。
can :read, Spree::Order do |order, token|
order.user == user || order.token && token == order.token
end
can :update, Spree::Order do |order, token|
order.user == user || order.token && token == order.token
end
can :create, Spree::Order
この設定項目はこう名言しています。注文を読み書きするためは、認証された正しいユーザーであること、正しいトークンが提示されていることの両方を満たす必要があります。
最後のステップは、認証が行われる際にトークンがCanCanに渡されることを明示し、コントローラ内で完結させています。
authorize! action, resource, session[:access_token]
クレジットカードのデータ
PCI コンプライアンス
全てのストアオーナーは、クレジットカード情報をPCIコンプライアンスに基づいて送信することを望まれている。SpreeはPCIコンプライアンスに関して絶対的な保障をするものではありません。(その他のこと、詳細についてはライセンスをご覧ください)我々ができることは、クレジットカードデータを一般的なセキュリティ対策のもと扱うことです。
Transmit Exactly Once
Spreeでクレジットカードを扱う場合に厳重に注意しなければならない点は、クレジットカードデータをSSL経由でSpreeに送信しなければならない点です。そのデータはすぐに選択した支払いゲートウェイに転送され、すぐに破棄されます。クレジットカードのデータはデータベースに保存されません(一時的には除く)そのデータはサーバー上のメモリに保存され、破棄される前にその用途に用いられます。
Payment Profiles
Spreeは'Payment Profile'の使用をサポートしています。これは、あなたのデータベースに顧客のクレジットカード情報を安全に__保存__することを可能にしています。より厳密に言うならば、クレジットカードを再利用するための「トークン」を保存することになります。クレジットカードゲートウェイは事実上クレジットカードを保存していることとなり、Spreeは繊細なクレジットカード詳細を保存することなく、同じカードで新しく課金することが可能になります。
Spreeは、Authorize.net CIMのペイメントプロフィールのサポート対象外です。
Other Options
サードパーティー製エクステンションであるPaypal's Express Checkout(厳密にはPaypal Expressと呼ばれている)このチェックアウトサービスのタイプはクレジットカード情報を外部にて扱います(あなたのサーバーはそのデータには一切触れない)そしてPCIコンプライアンスの要件を大幅に簡易化します。
また、Braintreeは興味深いゲートウェイオプションを提供しており、その利点はExpressCheckoutに似てサイト内でプロセスが行われているように見えることです。つまり、支払いの間、顧客は店を出ていないように見えます。彼らはこれを'transparent redirect'と読んでおり、BrainTreeのチームは彼らのゲートウェイを使用するRubyデベロッパー、彼らの製品を使うSpreeデベロッパーを助けています。
Security Alerts
Spreeは定期的に重要なセキュリティ、リリース情報をチェックします。あなたはそれらの情報を管理コンソールページから見ることができます。アラートは読了後、削除することもできます。自動チェックは、
“Configuration” => “General Settings”か、Spree::Config[:check_for_alerts]
をfalse
にすることで無効にすることができます。なお、インストール環境固有のアラートを出すために、チェックの際にいくらかの更新情報が含まれます。以下はアラートリクエストに含まれる構成情報の例です。
{
"name": "Spree Demo Site",
"rails_version": "3.1.1",
"version": "0.70.1",
"rails_env": "production",
"host": "www.spreecommerce.com"
}