2016/07/22

重複組合せでパスワードを生成し総当たり攻撃(Brute-Force Attack)をする

総当たり攻撃を行った場合は、不正アクセス禁止法 に違反し、3年以下の懲役又は100万円以下の罰金が科せられる。(不正アクセス行為の禁止等に関する法律 第11条 - 警察庁(PDF)
また連続で膨大なアクセスを行うため、DoS攻撃として威力業務妨害となる可能性もある。
絶対に行わないようにしてください。

セキュリティを学ぶ上で、防御側の立場しかしらないと適切な判断ができない思い、攻撃側の立場にたち、総当たり攻撃(Brute-Force Attack)のアルゴリズムを考えてみた。

総当たり攻撃(Brute-Force Attack)とは



総当たり攻撃とは、暗号の解読やパスワードの割り出しなどに用いられる手法の一つで、割り出したい秘密の情報について、考えられるすべてのパターンをリストアップし、片っ端から検証する方式。
総当たり攻撃 : IT用語辞典

もっとも原始的な暗号解読方法のひとつで、考えられるパターンをすべて試行する攻撃
たとえば3桁のダイアルロックがあれば、000、001、002〜998、999のようにすべてのパターン(3桁の数字であれば1000通り)を試行して、パスワードを解読する。

ただ、これではあまりにも時間がかかりすぎてしまうため、よく使われるパスワード(passwordやadminなど)をあらかじめ用意しておいて、その辞書をもとに攻撃する手法もある。



重複組合せでパスワードを生成し、総当たり攻撃を行う


今回は簡単に実装できたPythonと、ちょっと苦労したJavaScritpでの実装方法を紹介する

前提条件


クラックするパスワードの条件は以下のとおりとする。

  • 英字(小文字)のみ
  • 4桁

ちなみにこの条件で、次に紹介するプログラミングを使うと1秒以内にクラックできる。
実行環境やアルゴリズムにもよるが、秒殺、いやミリ秒殺だ。


Pythonの場合


import time
from itertools import product

target = 'pass'
chars = 'abcdefghijklmnopqrstuvwxyz'

def check(chars, repeat):
    pws = product(chars, repeat=repeat)

    for pw in pws:
        if ''.join(pw) == target:
            return ''.join(pw)


start = time.time()
pw = check(chars, 4)

if (pw is None):
    print('failure')
else:
    print('got it! -->', pw)

finish = time.time() - start
print(finish, ' sec');

Pythonの場合は、itertoolsproductを使うことで簡単に重複組合せの文字列を生成することができる。


JavaScriptの場合


const gen = (chars, repeat) => {
    var result = [];
    
    for (let i = 0; i < repeat; i++) {
        for (let j = 0; j < Math.pow(chars.length, repeat); j++) {
            result[j] = result[j] || [];
            result[j].push(chars.charAt((j / Math.pow(chars.length, i) ) % chars.length));
        }
    }
    
    return result;
};

const target = 'pass';
const chars = 'abcdefghijklmnopqrstuvwxyz';

const start = new Date().getTime();

const list = gen(chars, 4);
for (let pw of list) {
    if (pw.join('') === target) {
        console.log('success', pw);
    }
}

const finish = new Date().getTime();
console.log(finish - start, 'msec');

JavaScritpにはPythonのitertools.productみたいな便利な機能がないので、地道に重複組合せの文字列を作成する。genメソッドがそれに該当する。


このようにBrute-Force(力ずく)でクラックする。力こそパワーだ。
総当たり攻撃は、こんな原始的なのに有効だったりする。
パスワードがハッシュ化されていたって、暗号化されていたってお構いなし。
CPUを思いっきり使ってやてば、英字8桁くらいなら数秒〜数分でクラックされてしまう。


総当たり攻撃への対策


こんな単純な攻撃でも、単純なパスワードを利用しているとすぐにクラックされてしまう。そこで開発者視点と利用者視点の双方に立って、対策をまとめていく。

なぜ双方の視点が必要かというと、開発者がセキュリティ対策しても、利用者が単純なパスワードを使っていればすぐにクラックされる。
反対に、利用者が複雑で長いパスワードを使っていたとしても、開発者が十分なセキュリティ対策をしていなければ、これまたすぐにクラックされてしまうからだ。


開発者としての対策


  • 一定時間の試行回数を制限する
  • 一定速度以上の試行を禁止する
  • アクセス元を制限する
  • 不正ログイン試行が検知されたらアカウントをロックする
  • ワンタイムパスワードやセキュリティトークンを利用する
  • 二段階認証をする
  • パスワード強度チェッカーを提供する


利用者としての対策


  • パスワードの桁数を増やす
  • 英数字に加え、記号も使う
  • 想定されにくいパスワードを利用する


「パスワードの定期変更」は無意味?


組織に所属していると、3ヶ月ごとにパスワードを変えろと言われることがある。
この「パスワードの定期変更」はむしろ有害な場合もあるので、注意しなければならない。

まず、無害な場合は、利用者が個人の意志で変更する場合。

逆に有害な場合は、強制的に変更させる場合。
強制されると利用者は「覚えやすいパスワードを使おう」と思うようになり、安易なパスワードを利用することがある。

私は前職で同じような環境にあり「1qaz2wsx」「2wsx3edc」「3edc4rfv」……を延々と変え続けていた。このあたりは英数字混在8桁で古いパスワードチェッカーでは「強力」とでていたが、おそらく辞書攻撃(Dictionary Attack)されたら一発だろう。


この他にも心理的な理由から、セキュリティ的な理由などで「パスワードの定期変更」は必ずしも有効な手段ではないといえる。
もちろん「定期的に変更してはいけない」というわけではない。



参考文献


セキュリティについては、徳丸本(体系的に学ぶ 安全なWebアプリケーションの作り方)を読んでいただければ、だいたいのことが理解できると思う。
PHPのプログラムが付属しているので、実際に手を動かしながら読める良本だ。



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿