2016-11-02 26 views
0

在Udacity.com上有一門名爲Web Development的課程。 講師告訴我們關於cookies,如何簽署cookie,鹽是什麼,我們必須始終在數據庫中保存密碼散列。然後他給了我們一份家庭作業,然後他發表了一個解決方案。 只有在這裏我們看到了整個畫面:它們應該如何協同工作。Web開發中的鹽,散列和安全性

以下是適用於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. 爲什麼他混合使用用戶名進行哈希將密碼放入數據庫?

  4. 我們可以看到兩種製作哈希的方法:一種用於cookie,另一種用於數據庫。他們爲什麼分開?統一不是更實際:總是使用密鑰和鹽。代碼較少。而且安全性很好。但他分開了。爲什麼?

順便說The teacher's solution

回答

0

最重要的第一:這種方法用於存儲密碼是不安全的,不應該被使用,也不TEACHED。問題是,SHA-256的一次傳輸速度太快了(3 Giga SHA-256 per second),因此可能很容易被蠻橫壓制。我們需要BCrypt,PBKDF2或SCrypt中的成本因子。

一些問題的答案:

  1. 醃製弱密碼和強記號是兩回事。對於短/弱密碼來說,摳像和按鍵拉伸是必需的,但是可以省略強壯的標記。這要求參數val是一個強烈的隨機標記(最少20個字符a..z,A..Z,0..9)。這不能由所示的代碼來判斷,但應該是set_secure_cookie()文檔的一部分。
  2. 添加一個服務器端密碼到密碼哈希可以完成,但重要的是要了解你正在減輕和如何去做。如果你有興趣,看看我的tutorial關於安全密碼哈希。
  3. 混合用戶名不是散列密碼的常用方式,它不會提高安全性,但會阻止更改用戶名。
  4. 看到第一點。
+0

非常感謝。 – Michael