CoinomiWalletが何故秘密鍵の流出をしてしまったか雑に検証する
事の発端
このツイートにより、GoogleのスペルチェックAPIによってニーモニックが流出してしまっているとのこと。
SECURITY VULNERABILITY@CoinomiWallet sends your plain text seed phrase to Googles remote spellchecker API when you enter it! This is not a joke!
— Luke Childs (@lukechilds) February 27, 2019
Video attached for proof.
Credit goes to @warith2020 for finding the issue, read more from him here: https://t.co/tCZ0hDPyJ3 pic.twitter.com/hdaPOb84A9
なぜそんなことが起こったか気になったので調べてみる
下記のCoinomiWalletの公式サイトからMac版をダウンロードする
v1.0.5*1を本記事では検証しました。
Windows, Mac, Linuxと対応していたので、Electronを使っているのではないかと当たりをつけてました。
右クリック→パッケージの内容を表示
とすると、アプリのディレクトリが見れます。
ElectronではなくJavaだった!
coinomi-wallet-mac.jar をデコンパイルする
下記のデコンパイラを使用します。
chromium(Google Chromeのベース部分)で動いてそうなのが伺えます。
AppWindow.class
を確認してみると SpellCheckerService
というのが利用されてますが、 setEnabled(false)
とスペルチェックをオフにしています。
OAuthWindow.class
も同様にoffにされています。
あれ、offにされてるのに送信されるの?バグなの??
ここで冷静になる
「Twitterで報告されるような脆弱性対応終わってないわけないでしょ。修正済みなのでは?」
と思って、公式Twitter見てみたら・・・
Our official statement on the spell-check findings: https://t.co/o7Fmhn2FoI
— coinomi (@CoinomiWallet) February 27, 2019
公式声明が出てました。
そらそうですよね。
公式声明まとめ
chromiumとjxBrowser
jxBrowserというjavaのchromiumラッパー(?)がちょうど1週間前にアップデートされています。
chromiumがデフォルトでGoogleのAPIを利用して通信してしまうので、それをオフにできるような修正が入っていました。 セキュリティ要件等で厳しい時は、それをオフにするといいとのこと。
まとめ
- CoinomiWalletのデスクトップ版のみこのバグがあったが既に修正済み(自動でアプデ配信されているようです)
- chromium便利だけど、こういう時びっくり挙動があったりでびっくりする(かも)
*1:checksum: 39efb726c8993af435710be6fda4c9ab808f39b7601951168d3536979be649c0
恥ずかしながら私はPromiseのthenとcatchの順番に意味があるとは知りませんでした
どういうこと?
catch => thenで書いたときとthen => catchで書いたときの挙動が異なります。
次のコードを用意しました。
ボタンを左から順番に押してみるとどういうことかわかると思います。
See the Pen then catchの順番によって意図しないコードになる by serinuntius (@serinuntius) on CodePen.
そうです。最後のボタンを押したときだけ2回alertが出ましたね。
最後のボタンは catch => thenの順序で描いて、条件的にcatchに入るパターン
です。
使い分けると便利?かもしれません。おそらく大半のケースで then => catch という順序で書いた方が意図する実行結果になるということがわかりました。
今回はたまたまFirebaseのドキュメントを見ながら書いていて、catchが書いてあったからそこにthenを足したことで気づきましたw
Failed to load gRPC binary module because it was not installed for the current systemで怒られたときの対処法
なかなか解決しなかったので一応メモ。
環境
node: 10系
使用パッケージ
- electron
- firebase
対処法
1. nodeを9系にダウングレードする(あまり意味ないかも)
僕は ndenv
でnodeをインストールしているので
$ ndenv install -l |less $ ndenv install v9.11.2 $ ndenv global v9.11.2
node_modulesを吹っ飛ばす
$ rm -rf node_modules $ npm i
これでもまだ僕の場合駄目でした。
2. rebuildする
$ npm rebuild --runtime=electron --target=2.0.11 --disturl=https://atom.io/download/electron --abi=57
これで僕の場合解決しました。
参考
Q. ReactでHTMLをエスケープせずに突っ込みたいときは?
A
<div dangerouslySetInnerHTML={{ __html: '<a href="/hoge">HOGE</a>' }} ></div>
もちろん __htmlのところは変数でも大丈夫。
参考
新卒で入社して1年半ぐらい勤めた面白法人Kayacを退職しました
はじめに
この記事は ex-KAYAC Advent Calendar 2018 の15日目の記事です。
おそらくこのアドベントカレンダーの中で僕は最新の辞めた人ですね。今までと今後について書きたいと思います。
今まで
受託チーム(CL)時代
プラコレという、結婚式をしたいカップルと結婚式場をマッチングさせてチャットで予約できるサービスや、両家のレシピという新婚のカップルの両親からレシピ本を聞き出し製本するサービスの開発に携わっていました。
CLでは珍しい社内やグループのサービスと携わっていました。CLはクライアントの広告をお手伝いする系の案件が多い中、今思うと自分はあまりそういった案件には関わらなかったですね。
去年の11月末ぐらいに異動しないかというお誘いがあり、SG(ソーシャルゲーム)事業部に異動しました。
ゲームチーム時代
数年運用しているゲームに配属されました。
中規模のチーム開発や、運用が長いタイトルの大変さを学びました。
10ヶ月ぐらいそのチームで過ごして、そろそろ他のことをしようかな〜と思ってた頃にブロックチェーンと出会いました。
ブロックチェーンと出会ってから
BuildersconでEthreumを知り、DAppsというものを知りました。
現在サーバサイドのエンジニアをやっていますが、自分の仕事がなくなる、もしくは置き換わって行くな〜という気がして、すぐさま勉強しようと思いました。
ビルコンの2週間後にBitcoinのハッカソンがあるというをその前日ぐらいに気づいて、参加を決意しました。
そのハッカソンで優勝し、もっと実績を作りたいと思い、どんどんブロックチェーンのハッカソンに参加します。
- Tokyo Bitcoin Hackathon(優勝)
- Offchain Hackathon(Hashhub賞)
- BCHDEVCON in サンフランシスコ (優勝)
- 東京理科大学 ブロックチェーンハッカソン(SB Cloud賞、Cardano賞)
- State of Chain in ベトナム (決勝進出)
- Ontlogyハッカソン(準優勝)
2ヶ月強でこれだけのハッカソンに参加しました。さまざまな人と出会い、いろいろなアイデアや、様々なチェーンの開発をしました。
これから
株式会社を登記するだけの費用を稼ぐことが出来たら、起業しようと思ってます。
とりあえず今はブロックチェーンに関係ない便利なアプリケーションの開発をしていますが、それが一段落すればブロックチェーンを使ったちゃんとユーザにメリットがあるサービスを作りたいですね。
ほしい物リスト
退職エントリーを書くときにはほしい物リストのリンクを貼るのが通例のようなのではらせていただきます。
全て書籍です。(Kindle本は不可能らしいので、ギフト券にしました。応援してくださる方はwasab1gjがIDのGmailドメインに送ってください)
さいごに
会社を辞めたということをいうとよく聞かれるのが、「なぜやめたか?」なのですが、それは明確な答えが1つあります。
自分が成功しなかったことを会社のせいにしたくないからです。 100%の自由度で挑戦して、全て自己責任にしたかったのです。
会社のせいにするのってめっちゃダサいので・・・。
そんなこんなでこれから頑張っていきます。これからもよろしくお願いいたします。
GoのWebアプリケーションのSQLロガーとパフォーマンス分析ツールを作ってみた
はじめに
この記事は Go2 Advent Calendar 2018の記事です。
担当の10日より1時間ほど投稿が遅れてしまったことをお詫びします。
今回は、拙作のGo製のWebアプリケーションにSQLのクエリロガーを仕込めるOSS『graqt』 を紹介したいと思います。
過去に書いた記事を足して2で割ったような記事なので、graqtを知ってる方は読まなくてもいいと思います。*1
graqtとは
go-request-and-query-loggerです。
発音はガラクタでお願いします。
Go用のアクセスログとクエリのログを記録するためのhttp handlerミドルウェアで、そのログを解析するためのツールもついてます。
使い方
シンプルなWebアプリケーションの実装例
package main import ( "database/sql" "fmt" "math/rand" "net/http" "os" "time" _ "github.com/go-sql-driver/mysql" // 2つパッケージを追加してください "github.com/justinas/alice" "github.com/serinuntius/graqt" ) var ( // 2つ変数を追加してください traceEnabled = os.Getenv("GRAQT_TRACE") driverName = "mysql" db *sql.DB ) func init() { rand.Seed(time.Now().UnixNano()) } func main() { // ifを追加して 環境変数 GRAQT_TRACEが1のときだけログを吐きます。 // ISUCONで本番ベンチのときは オフにしておいたほうがいいと思います。 // しかし、パフォーマンスには結構気を使ったので、そんなに低下はしないと思います。 if traceEnabled == "1" { // driverNameは絶対にこれでお願いします。 driverName = "mysql-tracer" // もし、ログを吐く場所を変えたかったら以下のメソッドを呼んで下さい。 // デフォルトは、 query.logとrequest.logが このGoファイル(main.go)と同じディレクトリに出ると思います。 // graqt.SetQueryLogger("log/query.log") // graqt.SetRequestLogger("log/request.log") } var err error // ここを先程の変数に変更してください db, err = sql.Open(driverName, "root:@/graqt") if err != nil { panic(err) } defer db.Close() mux := http.NewServeMux() mux.HandleFunc("/user", createUser) // ミドルウェアを追加します。 var chain alice.Chain if traceEnabled == "1" { chain = alice.New(graqt.RequestId) } else { chain = alice.New() } // ミドルウェアを渡します http.ListenAndServe(":8080", chain.Then(mux)) } func createUser(w http.ResponseWriter, r *http.Request) { // contextを使用する方のメソッドに変えてください。 ctx := r.Context() stmt, _ := db.PrepareContext(ctx, "INSERT INTO `user` (email,age) VALUES (?, ?)") t1 := time.Now().UnixNano() age := rand.Intn(80) stmt.ExecContext(ctx, fmt.Sprintf("hoge%d@hoge.com", t1), age) w.Write([]byte(`ok`)) }
CLI部分
gocuiというパッケージを使って実装しています。
graqt夜の部の進捗。
— あおいちゃん⛓️ハッカソンマスター (@_serinuntius) August 17, 2018
今日はGIFにしてみた。
query windowを表示したり、閉じたりできるようになった!
リファクタして各windowごとのファイルにわけた。https://t.co/6JZQyklKlP#golang #isucon #graqt pic.twitter.com/xkkubqmeBi
今はこれより進化してて、普通に全部の情報が正しく表示されるはずです。
まとめ
ある程度便利なの作ったはずなので、煮るなり焼くなりしてあげてください。
#isucon 8 で 惨敗してきました
以下のレポートは書いてる途中で力尽きてしまい不完全なものです・・・。あらかじめご了承ください。
2018/09/15(土)にISUCON8に参加して、ボロ負けしてきたのでそのレポートです。
SlackでのやりとりやGitHubのコードをベースに、時間ごとに何をやったかをざっくり書いていきたいと思います。
メンバー
@serinuntius アプリケーション・エンジニア
@dozen (会社の同期) インフラ・エンジニア
@kazasiki (会社の先輩) アプリケーション・エンジニア
面倒なので、このレポートでは敬称略とさせていただきます。
10:00~10:30
ポータルログインして、レギュレーションを読む。同時にSSHのコンフィグを書いてました。
次のようなことを確認しました。
- ベンチマーが側の帯域がかなりでかい!
- PHPは動かすのにH2Oのコンフィグ書き換えなきゃいけないのか〜大変そうだな〜(まだ、このときはGo実装でもH2Oが動いてるとはしらず・・・。ちゃんと「PHP以外の実装」という言葉がでてきているのにね
GET /initialize
は10秒以内に返すなお、問題ページの内容はできるだけ最新の状態を反映させる必要がありますが、1秒以内の遅延は許されます。
非同期処理をおすすめするような文言アプリケーションは全て、保存データを永続化する必要があります。
これも気になった。
あと、ポータルを確認すると、ベンチマーカのIPアドレスが1つしか設定できないので、ロードバランスしないといけないんだろうな〜という話はしていました。
僕が alp, pt-query-diegest,dstat,notify_slack
を事前に用意してた温かみのあるコマンドの羅列を直接打って入れましたw
僕がGoの初期実装に変更して、ベンチ回すと1194でした。
topとかで負荷を確認したところ、すごくMySQLが支配的で、ループとかIndexやばそうだねっていう話をしました。
@kazasiki が、Redisを全台に入れてくれました。
10:30~
@kazasiki のMacがフリーズする
@dozen が ホスト名をつけてくれて、今何でログインしているかとか、通信もisu2とかでいけるようになる。
@dozenがスペックを貼ってくれる
スペック CPU: 2コア MEM: 1GB / swap 2GB
@serinuntius が alpの設定をNginxに入れようと思ったら、H2Oで動いていることに気がつく。
H2O全然わからんし、剥がしてNginx(open resty)で行こう!ってなった。
けど、この判断は結論からいうとミスだったかもしれない。 そもそも、H2Oはボトルネックではないし、ちゃんと動いてたし、なんならNginxよりパフォーマンスがいいという話を聞く。 alp形式のログにするのも、ちょっと調べてみるべきだった。
alpでボトルネックを調査して、初動を決めるというムーブが完全にできなくなってしまったので、レコード数の調査やアプリを読むことにした。 @dozenに、Nginx移行を進めてもらいながら、@serinuntius, @kazasikiはアプリを読むという割り振りになった。
MySQLのレコード数やIndexのサイズをパッと出してくれるSQLを、@serinuntiusが出す。
MariaDB [torb]> select -> table_name, engine, table_rows as tbl_rows, avg_row_length as rlen, -> floor((data_length+index_length)/1024/1024) as allMB, #総容量 -> floor((data_length)/1024/1024) as dMB, #データ容量 -> floor((index_length)/1024/1024) as iMB #インデックス容量 -> from information_schema.tables -> where table_schema=database() -> order by (data_length+index_length) desc; +----------------+--------+----------+------+-------+------+------+ | table_name | engine | tbl_rows | rlen | allMB | dMB | iMB | +----------------+--------+----------+------+-------+------+------+ | reservations | InnoDB | 192507 | 57 | 15 | 10 | 4 | | users | InnoDB | 5173 | 307 | 1 | 1 | 0 | | sheets | InnoDB | 1229 | 53 | 0 | 0 | 0 | | administrators | InnoDB | 101 | 162 | 0 | 0 | 0 | | events | InnoDB | 21 | 780 | 0 | 0 | 0 | +----------------+--------+----------+------+-------+------+------+ 5 rows in set (0.01 sec)
11:00 ~ アプリを読んでみる
@kazasikiとわいわいしながら、「何これ糞すぎ」「なにこれヤバイ」といいながらアプリを読んでいると、いくつかこれは確実にボトルネックになるであろうヤバポイントがあった。
getEvent, getEventsの「N+1」
こんだけの箇所で、getEventが呼ばれていた↓。
これを直すだけでも、だいぶ良さそう。
SHA2 の計算をわざわざMySQLに問い合わせて計算してもらっている
それ自体はそんなに重くないかもだけど、回数が多くなるとレイテンシが乗るしかなり無駄。
@kazasiki がざっと読んで、こんなメモを残していた。(原文ママ
* [ループクエリ]func getEventsからfunc getEventを読んでいて、getEvent内でsheetsやreserveを引いてる * 455行目totalPriceが毎回reserveをgroupbyしてsum()してるからまずい * 385行目/509行目でpasswordのsha2変換をmysqlにやらせている * 517行目でuserをもう一回引いてるけど無駄? * 533行のsanitizeEventはオブジェクトコピーがいらない気がする • 167行目のgetLoginUserが毎回ユーザ情報をdbから引いている
11:30〜
@dozenのNginxへの移行が終わり、やっとalpでの集計ができた。 ちなみにNginxへ移行してスコアが200点ほど落ちた。
こんな感じのコマンドを叩いてました。
[root@118-27-24-38 nginx]# cat access.log |alp --aggregates="/api/users/.*, /api/events/.*/sheets/.*/.*/reservation, /admin/api/events/.*/actions/edit"|less
/admin
と /api/users/:id
と /
が遅い。
予想通り、 getEvent
& getEvents
がネックぽいってなったので、@serinuntiusはそれを修正することにした。
@kazasikiはtotalPriceのSUMをどうにかすることになった。
12:30〜
N+1も酷いんだけど、SheetってUPDATEも走らないし、INSERTもDELETEも走らないので、cacheすれば良くない?と思って、 /initialize
でGoのメモリにキャッシュすることにした。
*1
ただ、cacheするだけじゃだめで、ハマった。何回かFailしてやっと意味がわかった。 ポインタ型を渡してしまうと、いろいろな処理でゼロ埋めみたいな処理とかが走って駄目だったみたい。
ポインタじゃなくて、実態を渡すことで回避した。 @kazasikiにいろいろと助けてもらった。
ただ、これはスコアにほぼ影響せず、12:38に score: 963
でマージした。
初めてのアプリの修正が競技開始2時間半って、
「うわっ・・・俺らのチーム遅すぎ・・・?」
ほぼ同時刻ぐらいに、@kazasikiの修正も終わったので、ブランチ変えて試してたら、Index貼るスキーマに ,
がなかったりして、修正してマージした。
12:54 score:1125
この2つの修正後のalp。まだgetEvent修正してないので、そんなに変化はない。
13:00〜
@serinuntius が getEventの修正をする。
@dozenがSlowログ出す。
@kazasiki は レポート作成時の不要なソートをしないっていうのをやっていた。 report作成時にやってる不要なソートを消す by kazasiki · Pull Request #6 · dozen/isucon8 · GitHub
15:00~
書くのも辛いが、getEventの修正にめちゃくちゃ時間がかかってしまった。
マージできたのは15時になった。
全部の関数には適当しなかったので、スコアは 1608
いろいろ自分がポンコツ過ぎて、@kazasikiにめっちゃ助けてもらった。 今思うと、常にペアプロで正確にガシガシ修正して行ったほうがよかったかもしれないと思った。
15:40~
別の箇所でもgetEventsを適用した。
score: 2289
17:00~
@kazasikiが直近の予約の取得を僕が作った、N+1改善後の関数にしてくれて、ここで大きくはねた。
スコアは 12635
。
なんかめっちゃ時間かかってしまったな〜という感じ。
*1:Goのメモリっていう表現はなんか変だけど、Redisではないっていうこと。