JINS PCの件について考えてみた
おさらい
入力フォームに改ざん、外部に情報送信の可能性:JINSに不正アクセス、約1万2000件のクレジットカード情報流出の可能性 – @IT
- カード番号
- カード名義人名
- セキュリティコード(カードの裏面などにある3〜4桁の数字)
- カード有効期限
ネットだと、カード番号を暗号化せずに保存していたのでは?とか、セキュリティコードを保存していたのか!とかいろんな指摘を受けていたようだけれども、入力フォーム自体が改ざんされて、ユーザーが入力した情報が外部に送信されてたようだ。
問題はこれから? - チャージバックの発生
JINS PCの今回の件のように、流出したカード情報はどうなるのか?を考えてみる。
クレジットカードの対面取引では、署名やカードの暗証番号を使い、カードの所有者しか再現できないもしくは知り得ない情報を使う事で、カードの正規所有者であることを認証している。
一方、インターネット決済のような非対面取引では主に4つの項目(カード番号、カード名義人名、セキュリティコード、カード有効期限)が利用されているケースが多い。したがってクレジットカード情報が流出すると第三者利用(不正利用)されてしまう可能性がある。
実際にJINSの件でも、7件の不正利用が確認されているらしい(2013/03/18現在)
では、第三者による不正利用が起きるとどうなるのか?この場合はチャージバックが発生する。チャージバックとは、ユーザー(=カードホルダー)が不正利用等により利用代金の決済に同意しない場合に、クレジットカード会社が加盟店(お店)に対して支払いを拒絶するというもの。
もちろん不正利用だけでなく、サービスそのものに不備があったりしてユーザーが支払いに同意せずにチャージバックになる(=お店側に不備がある場合)もあるけれども、不正利用のチャージバックはお店側にとってかなり痛い。
じゃ、どうすればいいの?
このままだとインターネットで商売したい加盟店はつらい。じゃどうしたらいいの?
例えば3Dセキュアによる認証をするという方法がとれる。
3Dセキュアとは、カード情報以外に各クレジットカード会社から発行されたインターネット専用のIDやパスワードを、ユーザーが入力しクレジットカード決済を行う仕組み。
下記のブランドあたりで提供されてたりします。
- Visa: Visa認証サービス(三井住友VisaだとVPass)
- Master: SecureCode
- JCB: J/Secure
3Dセキュアを利用すれば、盗難されたり情報が流出したカードや偽造されたカードに対しても、本人しか知り得ないID/パスワードを入力するため不正利用の可能性を大きく減らすことができる。
とはいえ、3DセキュアのID/パスワードをユーザーが忘れてしまうと購入機会を損失してしまう可能性もあるし、そもそもブランドによっては対応していないところも多いので、日本ではあまり進んでいない(海外だと結構使われている)印象。
まとめ
- JINSの件は、入力フォーム自体が改ざんされてユーザーの入力情報が外部に
- 流出したカード情報は、非対面取引で不正利用される可能性が高い
- 不正利用はチャージバックとなり加盟店(お店)は痛い
- 3Dセキュアを利用すれば不正利用を減らすことができるかも、ただしデメリットもある。
- もっと流行ればいいのに!
Vagrantを使ってみた
Vagrant
会社でMac Book Proがどうのこうので盛り上がっておりまして、Windowsでないと動かないアプリがあるとかないとかで盛り上がってます。ま、VirtualBoxとかで仮想化すればいいじゃんなんて思って調べてたら、Vagrant なんて凄いものが出てるんですね(びっくり)。
Vagrant を一言で言えば、Oracle VirtualBox を操作するコマンドラインツールってところでしょうか? rubyで記述されており、gemで簡単にインストールできたので紹介します。
VirtualBox のGUIをCUIで操作したいアレゲな人向けなツールです。
導入(for OS X Mountain Lion)
1) Virtual Boxをインストール
Virtual Boxは https://www.virtualbox.org/wiki/Downloads でダウンロードして通常通りインストールします。
2) Vagrantをインストールします。
Vagrantはrubyで書かれているのでgemでインストールできます。Gemfileに書いてbundlerでもいいけど。
$ gem install vagrant $ vagrant -v Vagrant version 1.0.7
3) ゲストOSの導入
ココに、vagrant用のOSイメージ(.boxファイル)一覧があるので選ぶ。
自分は、Scientific Linuxを入れてみました。
$ vagrant box add SFLinux http://lyte.id.au/vagrant/sl6-64-lyte.box [vagrant] Downloading with Vagrant::Downloaders::HTTP... [vagrant] Downloading box: http://lyte.id.au/vagrant/sl6-64-lyte.box [vagrant] Extracting box... [vagrant] Verifying box... [vagrant] Cleaning up downloaded box…
にしてもSFLinuxっていう名前にしたのは失敗。
4) 初期化(init)して起動(up)
$ vagrant init SFLinux (中略) $ vagrant up [default] VM already created. Booting if it's not already running... [default] Resuming suspended VM... [default] Booting VM... [default] Waiting for VM to boot. This can take a few minutes. [default] VM booted and ready for use!
早すぎワロタ
5) ログイン
起動は vagrant ssh コマンドで行います。
$ vagrant ssh Last login: Wed Sep 19 12:08:50 2012 from 10.0.2.2 [vagrant@localhost ~]$ uname -a Linux localhost.localdomain 2.6.32-279.el6.x86_64 #1 SMP Thu Jun 21 07:08:44 CDT 2012 x86_64 x86_64 x86_64 GNU/Linux [vagrant@localhost ~]$ cat /etc/redhat-release Scientific Linux release 6.3 (Carbon)
なにこれすごい、ここまで所要時間10分
(念のため)終了
終了時は別のターミナルから、haltコマンドを実行します。
$ vagrant halt [default] Attempting graceful shutdown of VM...
すると、vagrant sshしたターミナルで仮想マシンがシャットダウンされます。
[vagrant@localhost ~]$ Broadcast message from vagrant@localhost.localdomain (unknown) at 0:07 ... The system is going down for halt NOW! [vagrant@localhost ~]$ [vagrant@localhost ~]$ Connection to 127.0.0.1 closed by remote host. Connection to 127.0.0.1 closed.
YConnect(Yahoo! JAPAN)への認証をする「omniauth-yahoojp」を作ってみた
omnauth-yahoojpとは
railsとか各種ID(facebook, twitter, mixi, Googleなどなど)の認証機能を追加してくれるomniauthのYConnect(Yahoo! JAPAN)版を突貫で作ってみました(テストとか適当)。Github で公開しています。
ベースはomnioauth-oauth2で、Strategyという形でYConnectの機能を追加し、YConnectを最低限に利用できるようにしています。
git clone してもらい、gem build & gem install すれば利用できますが、自分でもだんだん面倒くさくなってきたのもあって、勢いで rubygems にもあげてます。
omniauth-yahoojp(0.1.0) - rubygems.org
gem install omniauth-yahoojp
ominiauth-yahoojpは、YConnect(OAuth2.0 + OpenID Connect)で認証・認可をした後に、UserInfoAPIにアクセスして、(なけなしの)ユーザー属性情報を取得する処理を簡単にします(これしかできないという)
事の発端
Yahoo! JAPANで開催されたOpen Hack Day Japan(2013/2/16〜2/18)の前哨戦、Open Hack Day Conference(2013/2/9)でYahoo! JAPANの代表としてYConnectの話をしました。
会場にて @makimoto 氏から、Rubyのライブラリないの?なんて話になり、おまけにtwitterでは下記のようにいつのまにかレースになっており(出来レース感もあるけど)とりあえず作ってみました(githubで公開中)
使い方
sinatraとかもありますが(よくわからないので)今回は、Ruby on Railsでの使い方を例示します。
1. Gemfileに追記する
gem 'omniauth-yahoojp'
2. Gemfileに基づいて必要なgemをインストールする
bundle install
3. config/initializers/omniauth.rb
config/initializers/omniauth.rbに以下を記載します。これは他のStrategy(facebook, twitter, mixi, Googleなどなど)でも同じ書き方です。
Rails.application.config.middleware.use OmniAuth::Builder do provider :yahoojp, ENV['YAHOOJP_KEY'], ENV['YAHOOJP_SECRET'], { :scope => 'openid profile email address' } end
client_idやclient_secretを直接記載しても良いですが、エレガントさに欠けるのでここは環境変数からとるようにします。
第4パラメータは Authorization エンドポイントで利用するパラメータです。UserInfoAPI で取得したい属性の scope を指定するほか、ログイン画面や同意画面の挙動を変更する :display, :prompt も指定できます。
4. config/routes.rb
Railsの中からYConnectで認証をする場合は、通常YConnectのAuthorization Codeエンドポイントにリダイレクトさせるのですが、omniauth-yahoojpではomniauth-yahoojpが提供している /auth/yahoojp に下記のような方法で飛ばします。
viewだとこんな感じ
<%= link_to "Yahoo! JAPAN でlogin", "/auth/yahoojp" %>
controllerだとこんな感じ
redirect_to /auth/yahoojp
YConnectから戻ってくる時は、 /auth/yahoojp/callback に自動的に戻ってくるようになっているので、これをコントローラにマッピングするために config/routes.rb に以下を記載します。
match '/top' => 'sessions#top' # toppage match '/auth/:provider/callback' => 'sessions#callback' #戻り先
これで SessionController クラスの callback メソッドが呼ばれるようになります。/top はなんとなくスタートページ(YConnectへのキック元)としました。
5. SessionControllerを記述する
rails g controller sessions
で SessionControllerクラス を作り、下記を記載します。
class SessionsController < ApplicationController def top render 'sessions/top' end def callback auth = request.env['omniauth.auth'] @user_id = auth.uid @name = auth.info.name @email = auth.info.email @first_name = auth.info.first_name @last_name = auth.info.last_name @token = auth.credentials.token; @refresh_token = auth.credentials.refresh_token; @expires_at = auth.credentials.expires_at; render 'sessions/callback' end end
認証結果は、 request.env['omniauth.auth'] の中に入ってきます。uid()でuser_idを、info()でUserInfoAPIで得られる属性が取得できます。
6. viewを記載
SessionsControllerにおいてrenderで指定したHTMLファイル(erb)を設置します。
app/views/sessions/top.html.erb
<h1>Hello! YConnect (Authorization Code Grant Flow)</h1> <div id="user_nav"> <%= link_to "Yahoo! JAPAN でlogin", "/auth/yahoojp" %> </div>
app/views/sessions/callback.html.erb
<div id="user"> <p>Hello, <%= @name %> さん</p> <div id="credentials"> Credentials: <ul> <li>access_token: <%= @token %></li> <li>refresh_token: <%= @refresh_token %></li> <li>expires_at: <%= @expires_at %></li> </ul> </div> <div id="userinfo"> UserInfo: <ul> <li>user_id: <%= @user_id %></li> <li>email: <%= @email %></li> <li>name: <%= @name %></li> <li>first_name: <%= @first_name %></li> <li>last_name: <%= @last_name %></li> </ul> </div> </div>
7. やっと起動
rails server
思うこと
omniauth-oauth2は、内部的にrubygemのoauth2を使っているせいか、RFC6749やRFC6750に完全に対応していないようです(コードのコメントではドラフト15になってますね)。
Authorization Code Grant Flow の token取得でBasic認証周りがつらい感じになっていたり、そもそもOpenID Connectに対応していないっぽいのでid_tokenが利用できない雰囲気に見えました。本当はできるのかな。。。
その他
rubyよりもpythonの方がかっこいいと思い(偏見)、rubyを全然やったこなかったので(言い訳)、全然なれていない感じで個人的にはだめだめな印象でございますので、なにかありましたらGitHubへpull requestください。
※あ、個人の創作物なので、所属組織とは関係ないよ!
ついでにとあるエンジニアのメモランダムというfacebookページもありますので、いいね!お願いします(宣伝)
iOS6.1の新機能「Advertising Identifierをリセット」を見てみる
はじめに
Advertising Identifierとは、文字通り広告識別子であるが、本機能は、iOS6.0から搭載されたAdvertising Identifierをリセットする機能のことらしい。
設定>一般>情報>アドバタイズ で設定をすることができる。
iOS6.0の時も「追跡型広告を制限する」というのがあるが、なぜ今回リセット機能が追加されたのかちょっと調べてみた(ググってみた)。
このIDの背景とか特徴とか
ざっくり言うと、このAdvertising Identifierの登場の背景と特徴は下記の通り。
[背景]
- UDIDへのアクセスは原則禁止(iOS5から非推奨になってたはず)
- UDIDの広告向けの代わりのIDとして、Advertising Identifier(スーパーCookie)が用意された
[特徴]
- これはデバイス固有ですべてのアプリで同じIDとなる
- 利用が許可されていればトラッキングに利用可能(デフォルトは利用許可になっている、なんてこったい)
- どうも簡単に変更されないっぽい(揮発性があると書かれてるけど)
で、リセットの必要性は
スーパーCookieは怖い、これはグローバル識別子だから個人と簡単に紐づけることができる可能性(名寄せできる可能性)があるということだよね。
しかもユーザーが利用を許可していなくてもこのデータの取得自体はできるようなので、トラッキングが抑止される保証がないと推測できる(DNTの実情と似ているな)。
だからこのIDをユーザー自身がリセットできる機能が必要だったと思う。
identifierForVendorとは?
Advertising Identifierについて調べていたら、iOS6からidentifierForVendorなるIDもあるらしい。
これはTeamID(アプリの開発ベンダー)ごとに同一となるUDIDっぽいものらしい。
開発ベンダーごとだからといって「かんたんログイン」の識別子として利用すると多分危険。
まとめ
- 「追跡型広告を制限する」をオフにしてもトラッキングされるかも
- きになったらAdvertising Identifierを(定期的に)リセットするといい
- identifierForVendorはベンダーごとに利用できるUDIDみたいなもの、ただし「かんたんログイン」的に利用していると、このIDの発行アルゴリズムがhackされると死ぬ
Cookieのexpireの扱いがブラウザによってちょっと異なる件
弊社のアプリが動かないという残念な問い合わせがいくつかあったので、1日ばかりずっと悶々と調べてみたりした。結局Cookieの挙動によるものだったんだけど、Cookieの有効期限の挙動がブラウザごとに違っているらしく、ちょっとハマッたので備忘録としてまとめてみた。
Cookieの仕様のおさらい
Cookieは、HTTP State Management Mechanism(HTTP 状態管理メカニズム)というタイトルで、RFC2965で定義されているみたいだが、各種ブラウザの実装は、Cookieを導入したNetscape Navigatorの実装に基づいているようだ。
ここでは、Cookieの仕様についての説明は割愛するが、超簡単にまとめると以下の通り。
- サーバ
- クライアントに保持してもらいたい状態情報を、HTTPレスポンスのSet-Cookieヘッダに乗せて送出する
Set-Cookie: NAME1=VALUE1; expires=DATE; path=PATH; domain=DOMAIN_NAME;
Set-Cookie: NAME2=VALUE2; expires=DATE; path=PATH; domain=DOMAIN_NAME;
- クライアント
- サーバから送られてきた状態情報を(有効期限内であれば)保持し、次回以降のリクエストにおいて、HTTPリクエストの"Cookie:"ヘッダに乗せて送出する
Cookie: NAME1=VALUE1; NAME2=VALUE2 ...
ここらへんは、Webサイトを構築するエンジニアは必須知識だと思う。
まずはCookieの動きを確認する
Net Applicationsによれば、2010年12月のブラウザ3大シェアは下記の通り。ということで下記3つのブラウザを調査対象とする。ちなみにクライアントはVista。あまり定評が良くないVista。
- 対象ブラウザ
- Internet Explorer
- Internet Explorer 8(8.0.6001.18999)
- Firefox
- Firefox 3(3.6.13)
- Chrome
- Google Chrome(8.0.502.237)
- Internet Explorer
ここで、検証に利用する予定のSet-Cookieするサーバ側のアプリケーションをさらしておく(PHPerですみません)。有効期限が600秒(=10分間)のtestcookieという名前のCookieを、phpのsetcookie関数で発行する単純なプログラムである。
[cookieを生成するサーバアプリケーション] http://192.168.1.101/setcookie.php 1 <?php 2 $currentTime = time(); 3 4 $cookieName = "testcookie"; 5 $cookiePath = "/"; 6 $cookieDomain = $_SERVER['SERVER_NAME']; 7 $cookieValue = strval($currentTime); // value is issue time (Unix Time) 8 $cookieExpire = strval($currentTime + 600); // expire is 10 minutes after issuing cookie 9 10 setcookie($cookieName, 11 $cookieValue, 12 $cookieExpire, 13 $cookiePath, 14 $cookieDomain);
ついでにサーバ情報はこんな感じ。
- ホスト
- 192.168.1.101 (プライベートIPでごめんなさい)
- OS
- 各種アプリ
ここでは、上記cookie発行プログラム(http://192.168.1.101/setcookie.php)にリクエストを送り、そのレスポンスヘッダとブラウザ側に蓄積されるcookie情報をブラウザごとに観察してみる。
Internet Explorer
通常のIEだとヘッダとかcookieの参照とか非力すぎて死ぬ。ヘッダ情報にはieHTTPHeaders、Cookieの参照にはInternet Explorer Developer Toolbar を導入した。Internet Explorer Developer ToolbarはMS純正。
- ヘッダ情報
- cookie情報
予想通り、Dateヘッダの10分後のExpireが設定されているtestcookieが発行され、それがブラウザにも保存されているようだ。当たり前か。
FireFox
FireFoxでヘッダの情報を確認するには、Live HTTP HeadersのAddonを導入。
- ヘッダ情報
- cookie情報
予想通り、Dateヘッダの10分後のExpireが設定されているtestcookieが発行され、それがブラウザにも保存され(略
クライアントとサーバの時刻を変えてみる
クライアントとサーバの時刻が同じとき(=同期しているとき)、CookieのExpire値の処理はブラウザを変えても変化はなかった。クライアントの時刻がサーバと同期されていない場合はどうだろうか?サーバの時刻が不正な場合なんて言語道断なので、クライアントの時刻を1時間早めた場合で検証してみる。検証内容は先ほどと同様で、10分間の有効期限を設定したcookieを発行したときのブラウザごとの挙動を確認してみる。
Internet Explorer
- ヘッダ情報 (クライアントのリクエスト時刻 = Mon, 31 Jan 2011 14:15:13 GMT ※1時間進んでるから)
- cookie情報
あれ、cookieが蓄積されていない。試しに同じドメインで別のHTMLをGETするときのリクエストヘッダを見てみる。もしCookieが有効ならば"Cookie:"ヘッダがサーバに向けて付与されているはずである。
- リクエストヘッダ情報
やっぱり、"Cookie:"ヘッダは送出されていない。この結果から推測されることは、IEでは"Set-Cookie:"のExpires値がそのまま評価され、クライアントのシステム時刻と比べて有効期限切れ(有効期限が過去の時刻になっている)と判断し、cookieに保存されなかったのではなかろうか?
FireFox
- ヘッダ情報 (クライアントのリクエスト時刻 = Mon, 31 Jan 2011 14:34:15 GMT ※1時間進んでるから)
- cookie情報
FireFoxはcookie情報が蓄積されているようだ。しかもクライアント側のリクエスト発行時刻+10分間の有効期限が設定されていることに注意したい。また、IEの場合と同様に別のHTMLをGETするときのリクエストヘッダを観察してみる。cookieの有効期限の10分間を意識して、cookie発行から10分以内と10分経過後を比べてみた。
この結果から推測されることは、Firefoxではサーバの意図したcookieの有効期限(=10分)がクライアント側の時刻に変換されてcookieに保存されるようである。おそらくレスポンスヘッダのDateヘッダとSet-CookieのExpires値の差分(=10分)を取得し、クライアントのシステム時刻(ただし今回は1時間進んでいる)に加えていると思われる。
まとめ
3大ブラウザのCookieのexpires値の処理
- Internet Explorer/Chrome
- HTTPレスポンスに含まれるSet-Cookieヘッダーのexpiresの値を厳密に利用しているようだ。
- Firefox
通常の利用がなされる場合には、両者の挙動にはまったく違いが見られないが、サーバとクライアントで時刻が異なる特殊なケースの場合に挙動が異なる可能性が出てくる。
クライアントとサーバの時刻が同期されていないとき
例としてクライアントが1時間時計を進めている時に、有効期限10分のcookieを発行した場合を考える。
- サーバ時刻
- Mon, 31 Jan 2011 10:00:00 GMT
- クライアント時刻
- Mon, 31 Jan 2011 11:00:00 GMT (1時間進んでる)
- cookie発行プログラムのレスポンス
- Date: Mon, 31 Jan 2011 10:00:00 GMT
- Set-Cookie: testcookie=1296481564; expires=Mon, 31-Jan-2011 10:10:00 GMT; path=/; domain=192.168.1.101
この場合は下記の挙動となる
結論
通常利用ではブラウザによるSet-CookieのExpire値の挙動に変化はないが、クライアントとサーバの時刻が同期されていないときは注意が必要かもしれない。
石垣島ファンダイビング
2010/6/5〜2010/6/6に石垣島ファンダイビングに行ってきた(人生初沖縄)。前回ライセンスを取ってから半年も経ってしまったのでorz、リフレッシュダイブをかねて行ってきた、わはーい。
写真の一部は、「海へ」さんの当日のブログよりお借りしてます^^;
今回ガイドをお願いしたショップは、嫁がx年前にもお世話になったという「海へ」というショップ。きょうのワンコにも出たというガジロウがお出迎え。
6/5(1日目)
初日は3Dive!
- コメント
- 見つけたもの
(Dive6)竹富島南ムーミン谷 | (Dive7)竹富島南ヨスジの根 | (Dive8)竹富島南海底温泉 | |
---|---|---|---|
深度 | 12.4(AVE10.3)m | 14.0(AVE10.2)m | 18.2(AVE8.6)m |
潜水時間 | 47分 | 49分 | 47分 |
気温 | 不明 | 不明 | 不明 |
水温 | 26.3℃ | 26.3℃ | 26.2℃ |
透明度 | 20m | 20m | 20m |
Ubuntu 8.04 LTS(hardy)にMySQL5.1をinstallする
はじめに
MySQLのパーティショニングとかQ4Mなどを試してみようと、Ubuntu 8.04 LTS(hardy)のMySQLのバージョンを確認したら、
mysql-server-5.0(5.0.51a-3ubuntu5.5)
MySQLのマニュアルには5.1からの新機能とのことなのでバージョンをあげたいけれども、Ubuntuのパッケージを見ても無いっぽいので、いろいろやってみるテスト。
手順
本家にはない!こういう残念なときには、世界中のハカーにお願いするのが常識。LaunchpadのPersonal Package Archive(以下、PPA)にお世話になってみる。Ubuntu8.10で試している人がいるので、8.04でも動くだろうと思って試してみる。
1. /etc/apt/sources.list に以下を追記
deb http://ppa.launchpad.net/monty/ubuntu gutsy main universe restricted multiverse deb http://ppa.launchpad.net/smurf/ubuntu gutsy main universe restricted multiverse
2. パッケージ情報更新
ubuntu% sudo apt-get update ubuntu% sudo apt-cache show mysql-server-5.1 Package: mysql-server-5.1 Priority: optional Section: misc Installed-Size: 54168 Maintainer: Debian MySQL Maintainers <pkg-mysql-maint@lists.alioth.debian.org> Architecture: i386 Version: 5.1.22rc-2~ppa5 (以下略)
入っているっぽい!「This package includes the server and ndb-cluster binaries.」と書いてあるのでndbも今度試さなきゃ。
3. UpgradeとInstall
ubuntu% sudo apt-get upgrade ubuntu% sudo apt-get install mysql-server-5.1
300個以上のパッケージのUpgrade。
1時間半ぐらいかかって mysqlのrootのパスワードの再設定を行って(といっても空にしたけど)インストール終了(`・ω・´)キリ!
ubuntu% mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 6 Server version: 5.1.22-rc-Debian_2~ppa5-log Debian lenny distribution Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>