それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Chrome(OSX)のパスワード・クッキーを取り出すコマンド作った

Mac OSX のChromeのパスワードを取り出すツールを書いた。

takuya/chrome-storage · GitHub

なぜ書いたのか

OSXChromeが、Keychains.app に同期しなくなったので、インポートするために仕方なく書きました。

いままではKeychainを見ればパスワードを回収できたのですが、OperaSafariFirefoxChromeがそれぞれ別管理になって、別々にアカウント同期でパスワードを持っていくのですが、どれが新しくてドレが古いか全くわからなくなりそうでした。

Chromeの管理からパスワード取り出せば良いのですが、chrome://settings/passwords のパスワードチェックがめんどくさい。ちょっと視認性の悪いUIですよね。

いままではローカルKeychainにパスワードつくってiCloudに移動すればよかったのに・・・Windowsの悪夢に逆戻りだ・・・

Opera/chrome のクッキーとパスワードのデコード

Chromium のパスワードは $PROFILE_PATH/Login Dataのファイルに保存されています。ファイルはSqlite3のデータベースになっています。そのファイルの中身でパスワードは暗号化されて保存されています。

暗号化されたパスワードは、Keychain.app にあるsafe storageに保存された文字列で復号化出来ます。

ダウンロード先

github.com

safe storage が幾つかある。

Opera(stable/beta) とChromeがそれぞれ使っています。

ここに保存されたパスフレーズでブラウザ中の暗号化データをデコード出来るようになっています。

f:id:takuya_1st:20151216034018p:plain:w600

暗号化・復号化処理も含めたブラウザのソースコードは公開されてるので、わたしたちはブラウザから平文でパスワードを得ることが可能になります。これからも安心して使える。ソース公開って素晴らしい

Firefoxはどうしてるんだろう・・・

パスワード・クッキーのデータベースの構造

パスワードとクッキーのデータベースは、次の通りのテーブル構造に格納されていました。

パスワードテーブル
CREATE TABLE   "logins"     (
    origin_url  VARCHAR    NOT   NULL    ,
        action_url  VARCHAR    ,
        username_element    VARCHAR    ,
        username_value  VARCHAR    ,
        password_element    VARCHAR    ,
        password_value  BLOB    ,
        submit_element  VARCHAR    ,
        signon_realm    VARCHAR    NOT   NULL    ,
    ssl_valid   INTEGER    NOT   NULL    ,
    preferred   INTEGER    NOT   NULL    ,
    date_created    INTEGER    NOT   NULL    ,
    blacklisted_by_user INTEGER    NOT   NULL    ,
    scheme  INTEGER    NOT   NULL    ,
    password_type   INTEGER    ,
    possible_usernames  BLOB    ,
    times_used  INTEGER    ,
    form_data   BLOB    ,
    date_synced INTEGER    ,
    display_name    VARCHAR    ,
    icon_url    VARCHAR    ,
    federation_url  VARCHAR    ,
    skip_zero_click INTEGER    ,
    generation_upload_status    INTEGER    ,
    UNIQUE      (
    origin_url  ,
        username_element    ,
        username_value  ,
        password_element    ,
        signon_realm    )
        )
        ;
クッキーテーブル
CREATE TABLE   cookies     (
    creation_utc    INTEGER    NOT   NULL    UNIQUE  PRIMARY KEY ,
    host_key    TEXT    NOT   NULL    ,
    name    TEXT    NOT   NULL    ,
    value   TEXT    NOT   NULL    ,
    path    TEXT    NOT   NULL    ,
    expires_utc INTEGER    NOT   NULL    ,
    secure  INTEGER    NOT   NULL    ,
    httponly    INTEGER    NOT   NULL    ,
    last_access_utc INTEGER    NOT   NULL    ,
        has_expires INTEGER    NOT   NULL    DEFAULT 1  ,
        persistent  INTEGER    NOT   NULL    DEFAULT 1  ,
    priority    INTEGER    NOT   NULL    DEFAULT 1  ,
    encrypted_value BLOB    DEFAULT '' ,
    firstpartyonly  INTEGER    NOT   NULL    DEFAULT 0  )
        ;

データベースからデータを取り出して、復号化

復号化はそんなに難しいものではなく、WEBを探したら色々出てきます。WindowsWin32を使っていて、linux/osxはキーチェンに保存したパスフレーズとhmacを使ったOpensslを使っているようだ

次の例は、ruby で復号化を試みた箇所です。 引数 passの部分は、Keychainから拾ってきます。

    def decrypt(encrypted_value, pass ) 
      iter = 1003
      key_len = 16
      salt = "saltysalt"
      iv = " " * 16

      return if encrypted_value.size < 3

      key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, key_len)

      cipher = OpenSSL::Cipher::AES.new(128,:CBC)
      cipher.decrypt
      cipher.iv = iv 
      cipher.key = key

      data = encrypted_value
      data = data[3,data.size]

      return cipher.update(data) + cipher.final
    end

取り出したID/PASSはKeychainに

security コマンド を使うことで、パスワードをKeychainに書き込むことが出来ます

 security add-internet-password -a ユーザー名 -s サーバー -w パス   -p 対象のフルURL  -U

これで、しばらくは生き延びられそうです。

関連記事

ChromeのCookieをプログラムから使う - それマグで!

chrome のCookieを取り出す。(暗号化Cookieの複合化でデコード済テキストを取り出す) - それマグで!

MechanizeでChromeのCookieを扱って面倒なログインを飛ばす - それマグで!

httpOnlyなCookieとは? - それマグで!

Chrome のパスワードがOSX Keychains に保存・同期しなくなった - それマグで!

find で指定のフォルダを除外するには

find コマンド結果多すぎて除外したいフォルダがありませんか?

find で除外したものといえば、.git や ruby だったら bundle/vendor など、find の結果から除外するには

find の -not オプションを使います

find は「検索条件」を列挙するタイプのコマンドなので、検索条件に -not をつけて否定形にすればいいわけです。

find . -not -iwholename '除外したい名前'
.git を無視する例。

一番使いそうなのがこれ。.git

find . -not -iwholename '*/.git/*'

-name と -iwholename とは?

find のオプションで、 -name と -iwholename は少し違う

  • -name : 自身のファイル名にマッチ
  • -wholename : 自身のファイルのパス名にマッチ
  • -iwholename : wholename のCaseInsensitive版

たとえば 、vendor/bundleについて -name / -iwholename でマッチすると

次のような結果になる。

名前 オプション 結果
vendor -name 'vendor' マッチする
vendor/bundle -name 'vendor' ×
vendor -iwholename 'vendor' マッチする
vendor/bundle -iwholename 'vendor' マッチする

のように検索結果のパス名(ディレクトリ名)にマッチさせることが出来る

-not -iwholename の意味

-iwholenameで .git をパス名に持つのをマッチさせて、それを -not で否定形にしている。

理屈がわかれば便利ですね

alias できない困った問題

.git を常に無視したいと思っても、find コマンドの性質上、検索パスは絞込条件の前に設置する必要がある。

find path -検索条件 -検索条件 -検索条件 #出来る
find  -検索条件 -検索条件 -検索条件  path # できない

そのために、alias をつけておくことが出来ない。

alias find="find $@ -not -name ss" # 出来ない

どうしてもやりたければfunctionを書くしか無いです。

function find { $( which find ) "$@"  -not -iwholename '*/.git/*'  ; }

関数書くしか解決策がないけども、function 使うのが手軽でベターな解決方法。

参考資料

http://stackoverflow.com/questions/2314643/how-can-i-get-find-to-ignore-svn-directories