質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

6790閲覧

JWTの署名検証をrubyではなくPHPで行いたい

aiueoao

総合スコア146

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2017/05/09 03:10

###実現したいこと
Android向けのアプリを作成中で、セキュリティの為にGoogleのSafetyNetを利用したいと思っています。

こちらのサイトを参考にさせて頂き途中までは進められたのですが、rubyを使った署名検証のところでつまづいています。訳あってサーバー側はrubyではなくPHPで実装したい為、参考サイトの署名検証の処理をPHPに書き換えたいのですが上手く出来ません。

サイトを参考にして

  • SafetyNetのライブラリを使って端末の情報をGoogleサーバーに送り
  • GoogleサーバーからのJWT(JSON Web Token)を端末が受け取り
  • 端末が自前サーバー(Apache)にJWTを送る

まで出来ました。

自前サーバーにて受け取ったJWTをLogに保存して、以下の事を試してみました。

  • JWTは"ヘッダ.ペイロード.署名" の順番にピリオド('.')で連結されているらしいので、ピリオドで分割
  • 分割したうちのペイロード部分をbase64_decodeした場合、正しいパラメータが表示されることを確認
  • ヘッダ部分をbase64_decode後にjsonDecodeすると

stdClass Object
(
[alg] => RS256
[x5c] => Array
(
[0] => 文字列
[1] => 文字列
)
}
となることを確認

  • 上記 x5cの各配列についてopenssl_x509_read ()など試してみましたがエラーが表示される [Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate!]
  • 署名部分をbase64_decodeした場合printでなにも表示されない

rubyのOpenSSL::X509::StoreのようなX509の証明書ストア(?)を作成して使う などといったことはPHPでは出来ないのでしょうか?
rubyは初めてなので調べながら進めていて、サンプルコードで理解出来ない個所も多々ありますがよろしくお願いします。

##該当のソースコード

ruby

1//参考にしたrubyコード 2require 'jwt' 3class InvalidLeafCertificate < StandardError; end 4class InvalidCertificateChain < StandardError; end 5 6X509_STORE = OpenSSL::X509::Store.new 7X509_STORE.set_default_paths #X509_STOREにて、システムの証明書が格納されているパスを代入するメソッド 8 9# 正しい署名の検証に成功すればtrue 10# 不正なものがあればfalse 11def improved_valid_jwt_signature?(jwt) 12 13 jwt = jwt.gsub(/(\r\n|\r|\n|\f)/,"") 14 ::JWT.decode(jwt, nil, true) do |header| 15 16 17 # 証明書チェインのすべての証明書をインスタンス化 18 certs = header['x5c'].map{|c| OpenSSL::X509::Certificate.new(Base64.decode64(c))} 19 20 # リーフ証明書の取り出し 21 leaf_cert = certs.first 22 23 # 証明書チェインの取り出し 24 cert_chain = certs.drop(1) 25 26 # リーフ証明書と今検証しようとしているホスト名の整合性の確認 27 unless OpenSSL::SSL.verify_certificate_identity(leaf_cert, 'attest.android.com') 28 raise InvalidLeafCertificate, "Certificate isn't issued for the hostname attest.android.com" 29 end 30 31 # 証明書チェインを用いて、証明書の正当性を確認 32 unless X509_STORE.verify(leaf_cert, cert_chain) 33 raise InvalidCertificateChain, "Certificate chain verification is failed" 34 end 35 36 # 検証に使った証明書たち 37 pp X509_STORE.chain 38 39 # JWT検証用の公開鍵を取り出す 40 leaf_cert.public_key 41 end 42 43 true 44rescue JWT::VerificationError, JWT::DecodeError, InvalidLeafCertificate, InvalidCertificateChain 45 false 46end 47 48################ 49# 実行サンプル用出力 # 50################ 51 52 53MAL_JWT = "#{不正なJWT(省略)}" 54SAFETYNET_JWT="#{SafetyNetAPIで取得した正規のJWT(省略)}" 55 56puts "malformed JWT" 57puts "result == #{improved_valid_jwt_signature?(MAL_JWT)}" 58puts "safetynet JWT" 59puts "improved_result == #{improved_valid_jwt_signature?(SAFETYNET_JWT)}"

###補足情報(言語/FW/ツール等のバージョンなど)
XAMPP ver7.0.8
Apache1.2.4.18(win32)
PHP7.0.8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

JWS ヘッダの x5c チェインに含まれる各証明書は、 DER (バイナリ) 形式の証明書を Base64 でエンコードしただけのもの かと思います。一方、 PHP の openssl_* 関数は 以前より PEM (テキスト) 形式しかサポートしておらず 、恐らく現在もそうなのだと思います。

というわけで、 openssl_x509_read() で開きたければ PEM 形式にきちんと直してやれば良いのですが、 PEM は殆ど DER の Base64 表現にヘッダ・フッタを付けただけのもの ですから、前掲の User Contributed Notes で示されているように、単純に以下ようなコードで変換してやれば良いのではないでしょうか。

php

1$pemCert = ( 2 "-----BEGIN CERTIFICATE-----\n" . 3 chunk_split($decodedHeader->x5c[0], 64, "\n") . 4 "-----END CERTIFICATE-----\n" 5); 6 7$cert = openssl_x509_read($pemCert);

ちなみに、 JWT の基本的な処理は php-jwt というライブラリがありますので、参考にしたり、使ってみたりすると良いかもしれません。

投稿2017/05/10 05:19

argparse

総合スコア1017

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aiueoao

2017/05/10 11:21

回答ありがとうございます。教えて頂いたとおりにやったら出来ました! まだrubyのコードが理解しきれませんが、php-jwtライブラリも使ってみようと思います。 本当に助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問