技術ブログを開設する
ログイン
もっと気軽にアウトプットできる技術ブログプラットフォーム
この投稿は別サイトからのクロス投稿です(クロス元:https://qiita.com/developer-kiki...

はじめに

Googleアカウント, Amazon, Twitter等、今時はアカウント制のサービスが溢れています。
これは仕事現場でも同様で、勤怠管理システムやredmine、github、slackと、関わる世界が広がれば広がるだけユーザーアカウントが増えていく。
こんなアカウント達のパスワード管理について、例えば1Passwordのようなツールで管理されている方も多いと思います。

ただ、中には「アプリに脆弱性が見つかって流出!が怖い…」なんて不安を持つ方もいるのかなと思ったり。
“パスワード管理”アプリの時点でそれは限界があるよな~、なんかいい手はないものかと。

「なにジョジョ?保管したパスワードの流出が怖い?
逆に考えるんだ、『流出しちゃってもいいさ』と考えるんだ」

ジョ、ジョースター卿!!そうだ!管理するのは補足情報だけにして、+キーフレーズを入力してパスワードを生成すればいいのでは!?
以降はパス”ワード”よりも文章で表現できるパス”フレーズ”という名称を使っていきます。

どんなもの?

実物はこちら(https://server.developerkikikaikaienjoy.work:60443/)に用意しました。

基本機能はこんな感じです。

  1. パスフレーズの生成(左枠)
    • Passphrase informationをベースに複雑なパスフレーズを生成します。
  2. Passphrase informationの管理
    • アカウントに対するPassphrase informationをベースに複雑なパスフレーズを生成します。
  3. アカウント管理(右枠)
    • Passphrase informationを保存するためのユーザーアカウントを管理します。

パスフレーズの生成

Passphrase informationの各項目を設定します。Keyphrase以外は覚えやすいフレーズを設定する想定です。

項目 概要 備考
Title TwitterやQiitaといった、対象サービス情報を入力 設定の識別子にも使います
Keyphrase 普段使っているパスワードを入力する
Algorithm select パスフレーズ生成に使用するハッシュアルゴリズムを選択する 選択肢変更でパスワード定期変更に対応可能
extra Info おまけ情報 ここもパスワード定期変更用に用意
max length パスフレーズ最大長 サイトによっては制限があるので
Use symbol in passphrase パスフレーズに記号を入れるか? サイトによっては記号必須
or 制限があるので

Passphrase informationの管理

1で扱う情報を毎回入力するのは面倒なので、Keyphrase以外をWebサーバー内に保存します。Save setting押下で設定を保存。
保存した設定は、右枠のPassphrase Settings内Get settingで一覧を取得。出てきたTitleをクリックすると左側の設定が更新されます。

サーバーにはpassphraseに関わる情報を保存しているわけではないので、サーバーの情報を得た時点でやっと攻撃のスタートラインに立てるという感じ。

認証は凝らずにDigest認証にしています。しょぼい

アカウント管理

上記管理を行う為のアカウントの管理をします。Createは認証なしで利用出来、UpdateとDeleteはそのまま。しょぼい

実際使えるの?

正直使ってみないと分かんないな、ということで公開しちゃおうと思いました。
逆に考えるんだ、『公開しちゃってもいいさ』と考えるんだ

(サーバー監視の仕組みはどのタイミングで入れておくもんなんだろうか?)

どうやって作ったの?

基本情報

パスフレーズ生成アルゴリズム

基本的な考え方はこのような感じです。

  1. サービス名+キーフレーズ+その他を結合した文字列を作成
  2. ハッシュ化
  3. 使える文字をフル活用してコンバート

最初は1, 2だけでいいかと思っていましたが、長さ制限のあるサイトもある && 記号、大文字も使えた方がいい(友人からのアドバイス)というわけで小細工を追加しました。
こういう仕組みを考える時間はほんと楽しいですね。こんな感じにしました。

  • 16進数と対応する文字テーブルを作る

ハッシュ値の各16進数文字を変換していくので、最初にテーブルを用意して数値⇒その位置の文字に変えます。

というわけでinitializeHashListで16進数と対応する16文字のテーブル作成。
記号なし向けには0-9,1-z,A-Z+利用頻度の低い(であろう)q, zを追加した64文字。
記号あり向けには上記に加えて記号32文字を加えた96文字を利用してテーブルを作成。

func initializeHashList() {  
    //テーブルを詰めるためのmap  
    wordsWithoutSymbol = make(map[int][]string, 0)  
    wordsWithSymbol = make(map[int][]string, 0)  
    /*記号なし向け*/  
    tmpWithoutSymbol := make([]string, 4);  
    tmpWithoutSymbol[0] = "0123456789abcdef";  
    tmpWithoutSymbol[1] = "ghijklmnopqrstuv";  
    tmpWithoutSymbol[2] = "wxyzABCDEFGHIJKL";  
    tmpWithoutSymbol[3] = "MNOPQRSTUVWXYZqz";  
    wordsWithoutSymbol[1] = tmpWithoutSymbol  

    /*記号あり向け*/  
    tmpWithSymbol := make([]string, 6);  
    _ = copy(tmpWithSymbol, tmpWithoutSymbol);  
    tmpWithSymbol[4] = "!\"#$%&'()*+,-./:";  
    tmpWithSymbol[5] = ";<=>[email protected][]^_`{|}~, ";  
    wordsWithSymbol[1] = tmpWithSymbol

同様に1byteと対応する文字テーブルも作成。
今度は長さが短くなる場合のテーブル作成。2文字=1byteなので256文字を利用しないといけないので、用意する文字が一気に増えます。。。
上で用意した記号なし64文字、あり96文字では足りないので何回か同じ文字を出すようにしています。コードは省略

  • 各16進数文字を変換

抜粋。hashTable構造体に上で用意したテーブルと何分の一にするか(16進何桁を1文字にするか)の情報を詰めます。
で、convertの中で16進文字を実値に変更してhexvalueに詰め、対応する文字テーブルの文字を取得します。

1/1スケールの場合は文字テーブルがいっぱいあるので、どのテーブルを使うかも実値+α情報で切り替えるようにしました。
(いい感じで使える文字をまんべんなく利用できることを期待しています)

type hashTable struct {  
    //文字テーブル  
    table []string  
    //何分の一にするのか?  
    scaledown int  
}  

func (this hashTable) convert(hashString string) string {  

    hexvalue := 0  
    result := ""  
    hashStringLength := len(hashString)  
    for i := 0; i < hashStringLength ; i++ {  
        hexvalue = hexvalue << 4//1 byte  
        tmpval, _ := hex.DecodeString("0" + string(hashString[i]))  
        hexvalue |= int(tmpval[0])  
        if (i % this.scaledown) == (this.scaledown - 1) {  
            index_table := (hexvalue + i) % len(this.table)  
            index_value := hexvalue % len(this.table[index_table])  
            result += string(this.table[index_table][index_value])  
            hexvalue = 0  
        }  
    }  
    return result  
}

単純な仕組みの組み合わせですが、使ってみるといい感じに散らばったパスワードが得られます。

メッセージ制御

クライアントとのメッセージはこんな感じにREST APIっぽくしました。
内部でメッセージを捌くためにこのような実装(override形式の方)を採用しています。

Digest認証

abbot/go-http-authを利用しました。詳細はこちら

その他

SSL/TLSで使用可能なcipher suiteの中で3DESを無効にするためechoに修正を加えています。詳細はこちら

後何する?

  • 画面をかっこよくする気はあまりない(誰か弄ってくれ!(笑)
  • 認証をかっこよくしたい
  • サーバー状態監視したい

参考

DB関連
MySQLインストール時にやること(DBとユーザーの作成等)
主キーの設定・削除、AUTO_ICREMENT属性の設定
外部キー制約
MySQLでGo
Go, echoのtemplate操作で使う構造体はグローバルにしようぜって話
Simple if not working go template

golang, ハッシュアルゴリズムサポート一覧
https://golang.org/pkg/crypto/
各API
https://golang.org/pkg/crypto/sha256/
https://golang.org/pkg/crypto/sha512/
https://godoc.org/golang.org/x/crypto/blake2s
https://godoc.org/golang.org/x/crypto/blake2b

タイトル参考
「逆に考えるんだ」を使う5つのポイント

関連記事

この記事へのコメント

まだコメントはありません
10
@dOpIa1PQNPi5jLrnの技術ブログ
10
このエントリーをはてなブックマークに追加