はじめに
こんばんは。
先週ちょっと体調悪くて、ブログ上げるのが遅くなりました。
自分が現在作成中の簡単なサービスで、パスワード認証部分にbcryptを使ってハッシュ化しようとしています。
phpであれば、 password_hash($password, PASSWORD_BCRYPT);
とかで簡単にできちゃうのですが、現在勉強中のGo言語でやるにはどうするのだろうと思って、調べてやってみました。
やってみた
今回試すパスワードは 1qaz2wsx3edc
で統一しています。
各バージョンは以下です。
$ php -v PHP 7.3.1 (cli) (built: Jan 21 2019 12:58:05) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies with Xdebug v2.7.0beta2-dev, Copyright (c) 2002-2018, by Derick Rethans $ go version go version go1.11 darwin/amd64
Go言語でパスワードハッシュ化
実装は、こちら のサイトを参考にさせていただきました。
実装
package main import ( "fmt" "golang.org/x/crypto/bcrypt" ) func main() { password := "1qaz2wsx3edc" hashedPassword, hashError := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if hashError != nil { panic(hashError.Error()) } fmt.Println(string(hashedPassword)) }
結果
$ go run main.go
$2a$10$YDZISuUQVTcza4uIM71m/uAZeGToP7SSDcxMbmtIojP2hJWzGQFPO
こんな感じです。
これで検証は終わったんですが、ふと
「Golangでハッシュ化したパスワードはphpで突き合わせできるのかな?」
と思ってやってみました。
phpでパスワード検証
実装
<?php $password = "1qaz2wsx3edc"; $hashedPassword = $argv[1]; if (password_verify($password, $hashedPassword)) { echo "OK\n"; } else { echo "NG\n"; }
結果
$ php password_verify.php '$2a$10$YDZISuUQVTcza4uIM71m/uAZeGToP7SSDcxMbmtIojP2hJWzGQFPO' OK
通りました。 まぁ同じアルゴリズムだから通るよねと、予想通りでした。
Go -> phpを試してみたので、 php -> Goも試してみました。
phpでパスワードハッシュ化
実装
<?php $password = "1qaz2wsx3edc"; $hashedPassword = password_hash($password, PASSWORD_BCRYPT); echo "{$hashedPassword}\n";
結果
$ php password_hash.php
$2y$10$hooq151ubdNmdlihER7PEenSG53YIPylUdkjljEwkmEpJ2Hk16paW
出来上がりました。これを今度はGo言語で検証します。
Go言語でパスワード検証
実装
package main import ( "os" "fmt" "golang.org/x/crypto/bcrypt" ) func main() { password := "1qaz2wsx3edc" hashedPassword := os.Args[1] err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) if err != nil { fmt.Println("NG") } else { fmt.Println("OK") } }
結果
$ go run main.go '$2y$10$hooq151ubdNmdlihER7PEenSG53YIPylUdkjljEwkmEpJ2Hk16paW' OK
通りました。こちらも想定通りです!
phpで作成した場合とgolangで作成した場合でハッシュ値が違うことに関しては、こちらに詳しく書かれていました。
暗号化のバージョン
上記のサイトで紹介されている「暗号化のバージョン」のところで、phpで作成した場合は 2y
でgolangの場合は 2a
が少し気になったので調べたところ、こちらのサイトに詳しく書かれていました。
以下、引用です。
BCrypt を表すバージョンは、$2$ $2a$ $2b$ $2x$ $2y$ が存在するようです。
・$2$ (Provos・Mazières, 1999)による最初のBCrypt。
・$2a$$2b$ のいくつかの実装に存在するセキュリティ上の問題を修正したバージョン。
・$2x$ crypt_blowfish の $2a$ に存在していた問題を修正する前と同一のバージョン。
・$2y$ crypt_blowfish の $2a$ に存在していた問題を修正した後と同一のバージョン。
・$2b$ 公式の BCrypt の最も新しいバージョン。
Golangの場合は決め打ちで、2a
になっているみたいです。
https://github.com/golang/crypto/blob/master/bcrypt/bcrypt.go#L57-L58
phpの場合は、参考サイトにも記載されているのですが、 php自体のバージョンによって 2a
でも一部問題が発生するパターンがあるとのことで、php7など、最近のバージョンを使う場合は 2y
を使うことで問題ないということでした。
終わりに
ちょっと気になって調べてるうちに、どこまで調べたらいいのかわからなくなってきたので、一旦やめました。
地味にGoのコマンドラインからの引数を受け取る flag
パッケージも初めて使いました。
現場からは以上です。
追記
ありがたい指摘をいただきましたので、追記します。
自分は「コマンドラインからの引数をもらえる」ような認識でいたのですが、それは、取ろうと思えば取れるという感じで、実際の使い方とは違うようです。
今回の自分の使い方でいうと、osパッケージで問題ないということでした。
該当のコードも修正しておきました。
ありがたや。