簡體   English   中英

從 Flask 中的登錄表單安全地發送密碼

[英]Securely send passwords from login form in Flask

我有一個使用會話的簡單登錄功能的網站。 我認為它是安全的,因為我正在對密碼進行散列和加鹽,但我意識到實際(可能)發生的是我在 POST 請求中將明文密碼發送到服務器,然后我才對其進行散列和加鹽. 我以為我了解如何管理密碼,但現在我想知道該怎么做。

這是我的代碼:

import bcrypt
from argon2 import PasswordHasher, exceptions
import db as database

ph = PasswordHasher()


@app.route("/login", methods=["POST", "GET"])
def login():
    if check_logged_in(session, 0):
        return redirect("/index")
    else:
        error = ""  # set to nothing unless we get error below
        if request.method == "POST":  # if user submits form
            username = request.form["username"]  # retrieve username from form
            password = request.form["password"]  # retrieve password from form
            if verify_login(username, password):  # if their login is valid
                session["username"] = username  # update session with their username and redirect them to index
                return redirect("/index")
            error = "Invalid username or password"  # else update the error message
        return render_template("login.html", error=error)  # and return login with error message


def verify_login(username, password):
    db_hash, salt = database.retrieve_pw_salt(username)  # gets hashed/salted password and salt from database given a username
    if db_hash is None:
        return False  # invalid username
    try:
        ph.verify(db_hash, salt + password)
        return True  # valid username and password
    except exceptions.VerifyMismatchError:
        return False  # invalid password


def check_logged_in(session, required_privilege):
    if "username" not in session:
        return False  # not logged in
    elif session["username"] == "admin":
        return True  # logged in as admin
    elif session["username"] == "reception" and required_privilege <= 1:  # checks to ensure a reception isn't trying to access admin pages/features
        return True  # logged in as reception
    elif session["username"] == "teacher" and required_privilege == 0:  # checks to ensure a teacher isn't trying to access admin/reception pages/features
        return True  # logged in as teacher
    return False  # else not logged in

我想我認為這段代碼會在客戶端運行,但我認為不是。 在這種情況下,我怎樣才能將我的用戶的 salt 放到客戶端,然后將它與密碼結合起來,對它進行哈希處理,然后才將它發送到我的服務器?

如果這有所不同,我的服務器在 Ubuntu 18.04 上運行帶有 uWSGI 的 Nginx。

謝謝。

編輯:順便說一下,這就是我首先生成鹽的方式:

def generate_salt():  # creates a salt
    salt = bcrypt.gensalt().decode("utf-8")
    return salt

從攻擊者的角度來看,客戶端散列不提供額外的安全性。 請參閱https://security.stackexchange.com/questions/62280/client-side-hashing-of-password-before-sending-it-from-login-form

我正在使用 HTTPS,但我認為這也被使用了。

所有安全措施都需要清楚地了解它們將保護您免受什么侵害,您需要做什么取決於您要覆蓋的攻擊媒介。

您似乎擔心有人可以在傳輸過程中讀取密碼:

但我意識到實際上(可能)發生的是我在 POST 請求中將明文密碼發送到服務器

但是,當您說在使用 https 時密碼以純文本形式發送時,您是不正確的。 Https 意味着服務器和瀏覽器之間的通道是加密的,並且......被認為是安全的(*)。 加密兩次不會增加任何安全性,即使看起來做更多的工作應該會給你“一些東西”。

如果您試圖防范控制瀏覽器或客戶端計算機的攻擊者,那么再多的客戶端加密也無濟於事; 如果您試圖防范控制服務器的攻擊者,情況也是一樣的。

一種可能泄露密碼的情況是 POST 期間未處理的異常。 大多數網絡應用程序通過電子郵件或 Sentry 等服務報告此類錯誤。 Web 框架通常有一種減輕這種情況的方法,它比客戶端加密更通用,更易於使用(例如 Django 的@sensitive_post_parameters(...) https://docs.djangoproject.com/en/2.1/howto /error-reporting/#django.views.decorators.debug.sensitive_post_parameters )。

您將使用客戶端加密的一種情況是,如果用戶想要在服務器上存儲/檢索服務器管理員不應該讀取的數據。 服務器無法與數據交互,因此它不是登錄期間密碼的用例。

(*) 如果您想防范可以解密 https 通道的人,那么您就超出了正常網站登錄表單所需的范圍(如果您為 NSA 工作,您可能應該在內部詢問而不是在 SO ;-)

ps:你可能不應該 decode('utf-8') bcrypt.gensalt() ) 的結果——我沒看過,但我無法想象它會返回 utf-8 數據。

附錄:並非所有二進制數據都是 utf-8。 base64是一種創建 unicode 表示的方法:

>>> b = b'\xc3\x28'   # byte sequence that is not valid utf-8
>>> b.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 0: invalid continuation byte
>>> import base64
>>> base64.b64encode(b)
b'wyg='
>>> base64.b64encode(b).decode('ascii')
'wyg='
>>>

這是一個老問題,但我想知道同樣的事情,所以我想我應該與以后可能會發現它的人分享我的發現。

大多數網站不會更改客戶端的密碼。 有兩個原因。

  1. 對客戶端散列的支持確實不多。 例如,Javascript 不支持 SHA。

  2. 散列客戶端實際上並沒有使站點更加安全。 MITM 攻擊者可以更改 javascript 並簡單地關閉散列。 因此,實際上,它只會有助於防止被動窺視。

下面是一些線程幫助我理解: https://security.stackexchange.com/questions/53594/why-is-client-side-hashing-of-a-password-so-uncommon HTTPS://security.stackexchange。 com/questions/42062/how-do-you-verify-if-an-app-is-using-secure-comms

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM