2016-11-02 8 views
0

Udacity.comにはWeb Developmentというコースがあります。 講師は、クッキー、クッキーの署名方法、塩の種類、データベースのパスワードを常にハッシュしなければならないことについて教えてくれました。それから彼は私たちに宿題を与えて、解決策を発表しました。 ここでは、全体像を見てきました。ウェブ開発における塩、ハッシュ、セキュリティ

以下はGoogle App EngineのPythonとコードです。しかし、してください、恐れてはいけません。コードは擬似コードのように読めるようです。 質問は一般的で、この特別な技術についてではありません。

import hashlib 
import hmac 

secret = 'iamsosecret' 

def make_secure_val(val): 
    return '%s|%s' % (val, hmac.new(secret, val).hexdigest()) 

def check_secure_val(secure_val): 
    val = secure_val.split('|')[0] 
    if secure_val == make_secure_val(val): 
     return val 

def make_salt(length = 5): 
    return ''.join(random.choice(letters) for x in xrange(length)) 

def make_pw_hash(name, pw, salt = None): 
    if not salt: 
     salt = make_salt() 
    h = hashlib.sha256(name + pw + salt).hexdigest() 
    return '%s,%s' % (salt, h) 

def valid_pw(name, password, h): 
    salt = h.split(',')[0] 
    return h == make_pw_hash(name, password, salt) 

class User(db.Model): 
    name = db.StringProperty(required = True) 
    pw_hash = db.StringProperty(required = True) 
    email = db.StringProperty() 

    @classmethod 
    def register(cls, name, pw, email = None): 
     pw_hash = make_pw_hash(name, pw) 
     return User(parent = users_key(), 
        name = name, 
        pw_hash = pw_hash, 
        email = email) 

    @classmethod 
    def login(cls, name, pw): 
     u = cls.by_name(name) 
     if u and valid_pw(name, pw, u.pw_hash): 
      return u 


class BlogHandler(webapp2.RequestHandler): 

    def set_secure_cookie(self, name, val): 
     cookie_val = make_secure_val(val) 
     self.response.headers.add_header(
      'Set-Cookie', 
      '%s=%s; Path=/' % (name, cookie_val)) 

    def read_secure_cookie(self, name): 
     cookie_val = self.request.cookies.get(name) 
     return cookie_val and check_secure_val(cookie_val) 

    def login(self, user): 
     self.set_secure_cookie('user_id', str(user.key().id())) 

    def logout(self): 
     self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/') 

    def initialize(self, *a, **kw): 
     webapp2.RequestHandler.initialize(self, *a, **kw) 
     uid = self.read_secure_cookie('user_id') 
     self.user = uid and User.by_id(int(uid)) 

ここにある内容を精査しましょう。

  1. 機能make_secure_valはこのような何かを生成します。 'キーワード| 6f21001bbf8bfbd8c04b9d537df1e314'
  2. 機能make_secure_valは、関数set_secure_cookieに使用されています。したがって、ログインに使用されます。
  3. 関数make_secure_valは秘密鍵を使用しますが、saltは使用しません。
  4. 機能make_pw_hash(名、PW、塩=なし)は、このような何かを生成します:「some_salt、c984cade696390b71ff914293c53767502ea542bfd0e7240a051e7ead2c60077」
  5. 機能make_pw_hashはデータベースに保存されるハッシュされたパスワードを準備します。ユーザーがユーザー名とパスワードをフォームに入力すると、フォームからのデータがこのmake_pw_hash関数の引数になります。
  6. 機能make_pw_hashはsaltを使用しますが、秘密鍵は使用しません。
  7. 何らかの理由でmake_pw_hash関数がユーザー名をハッシュに混ぜたものです。

ここでは何も分かりません。私はこれがすべて安全ではないと言います。

質問:先生はクッキーのための塩を使用していないのはなぜ

  1. なぜパスワードをデータベースに入れるために秘密鍵を使用しなかったのですか?

  2. なぜパスワードをデータベースに入れるためにハッシュを作成するためにユーザー名を混ぜたのですか?

  3. ハッシュを作成するには、Cookie用とデータベース用の2つの方法があります。なぜ彼らは分かれていますか?統一するのが現実的ではありません。常に秘密の鍵と塩を使います。少ないコード。そして良いセキュリティ。しかし、彼は分かれた。どうして?

The teacher's solution

答えて

0

ちなみに最も重要な最初:パスワードを格納するためのこの方法は安全ではありませんし、使用もteachedすべきではありません。問題は、SHA-256の1回のパスが速すぎる()ため、ブルートフォースが余りにも簡単すぎることです。 BCrypt、PBKDF2、またはSCryptで利用可能なコスト要因が必要です。ご質問

いくつかの答え:

  1. 塩漬け弱いパスワードと強力なトークンは、二つの異なるものです。短くて弱いパスワードには塩分とキーストレッチが必要ですが、強いトークンには使用できません。そのため、パラメーターvalは強力なランダムトークン(最小20文字a..z、A..Z、0..9)である必要があります。このコードでは判断できませんが、set_secure_cookie()のドキュメントの一部である必要があります。
  2. パスワードハッシュにサーバーサイドのシークレットを追加することはできますが、軽減するものとそのやり方を理解することが重要です。興味があれば、安全なパスワードハッシュについて私のtutorialを見てください。
  3. パスワードをハッシュするのは一般的な方法ではありませんが、セキュリティは向上しませんが、ユーザー名の変更はできません。
  4. 最初の部分を参照してください。
+0

ありがとうございました。 – Michael

関連する問題