TIL-認証(認証)と認証(認証)

4921 ワード

Authentication


認証はプレイヤーの身元を確認するプログラムです.
ユーザのアイデンティティとパスワード生成フェーズでは,パスワードを暗号化してDBに保存し,ログイン時にユーザが入力したパスワードを暗号化して,暗号化してDBに保存したユーザパスワードと比較する.
ログインに成功するとaccess tokenがクライアントに送信され、ログインに成功するとaccess tokenが追加されてrequestがサーバに送信され、毎回ログインする必要はありません.

ユーザーパスワードの暗号化


データベースがハッカーに攻撃されてもパスワードが露出しないように、内部の人もパスワードを知らないように、ユーザーのパスワードは必ず暗号化して保存しなければならない.
パスワード暗号化には、通常、一方向ハッシュ関数が使用されます.
一方向ハッシュ関数は、元のメッセージを変換することによって暗号化されたメッセージ다이제스트(digest)を生成する.
オリジナル情報がわかれば容易に暗号化された情報を得ることができるが、暗号化された情報はオリジナル情報を得ることができないため、단방향성(one-way)と呼ばれる.
ex)hash 256という関数「test password」を使用する場合、値は0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094eです.
「test password 2」がhash 256関数を使用する場合、値はd34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aebです.実際のパスワードは似ていますが、ハッシュ関数の数値はまったく異なります.この効果を変卦と呼ぶ.(暗号ハッシュ値の復号が困難になる要因)

一方向ハッシュ関数の弱点


  • Rainbow table attack:ハッシュ値をあらかじめ計算したテーブルをRainbow tableと呼ぶ.

  • ハッシュ関数は,もともと暗号を格納するために設計されたものではなく,短時間でデータを検索するために設計されたものである.したがってハッシュ関数は本来,処理速度が最も速いように設計されているが,これらの属性により,攻撃者は任意の文字列の要約と攻撃するオブジェクトの要約を極めて速い速度で比較することができる.(MD 5を使用する場合、従来のデバイスを使用して毎秒56億個の要約をダンプできます)
  • 一方向ハッシュ関数の不足を補う


  • Salting:ハッシュ値を計算する方法で、実際のパスワードのほかにランダムなデータを追加します.

  • KeyStretching:一方向ハッシュ値を計算し、ハッシュ値をハッシュし、ハッシュ値を繰り返します.最近では、通常装備で毎秒50億個以上のDigestを比較できるようになったが、鍵を使ってストレッチし、同じ装備で毎秒5回程度しか比較できない.グラフィック処理ユニット(GPU)を用いても数百〜数千回の比較しかできない.
  • SaltingとKey Stretchingを実現するハッシュ関数で最も広く用いられているのはbcryptである.bcryptは,最初からパスワードを一方向に暗号化するために作成されたハッシュ関数である.
  • bcrypt暗号化方法


    bcryptはstrデータではなくBytesデータを暗号化するので、暗号化時にバイト化する必要があります.
    Pythonでは、strをバイト(進化)に符号化し、strにバイトを復号する.
    「UTF-8」Unicode文字仕様を使用して、encode、decodeで認識できるフォーマットに変換します.
    <暗号化>
    password = '1234'
    hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
    print(hashed_password)
    b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'
    <暗号化パスワードの検証>
    new_password = '1234'
    bcrypt.checkpw(new_password.encode('utf-8'),hashed_password)
    True
    bcrypt.checkpw()メソッドのルール:(入力したパスワード、保存した暗号化パスワード)
    両方のデータ型はBytesでなければなりません.

    JWT


    ログインに成功すると、access tokenという暗号化されたユーザ情報が添付されてrequestが送信されます.
    <ユーザログイン>
    POST /auth HTTP/1.1
    Host: localhost:5000
    Content-Type: application/json
    
    {
        "username": "joe",
        "password": "pass"
    }
    < access token >
    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
    }
    これにより、サーバは、access tokenを復号して、対応するユーザ情報を取得する.
    ex)accesstoken eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_Eを復号すると、以下のユーザIDが得られ、これらのユーザによってそのユーザが誰であるかを知ることができる.
    {
        user_id = 1 
    }
    access tokenを生成する方法はいくつかありますが、最も一般的な技術の1つはJSON Web Tokens(JWT)-ユーザ情報を含むJSONデータを暗号化し、クライアントとサーバ間で交換する

    JWT実装

    access_token = jwt.encode({'id' : 1}, SECRET, algorithm = 'HS256')
    print(access_token)
    'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'
    pyjwtのバージョンによっては、jwtの成果物はbytes(ver.1.7)タイプであってもよいし、str(ver.2.0以降)タイプであってもよい.
    (インストールしたpyjwtのバージョンを特定し、jwtのecode結果のタイプに応じてbtyesstrのプロセスを行います.)
    検証されたコードは、通常user app上でutlsを使用するエンドポイントでデコーダとして実装される.pyを作成して作成します.

    Authorization


    認証は、ユーザが要求を実行する権利のあるユーザであるかどうかを確認するプログラムである.

  • 認証プロセスの使用  access tokenを生成します.  access tokenは、ユーザIDなどのユーザ情報を表示できる情報を含むべきである.

  • プレイヤーがリクエストを送信すると  access tokenを添付します.

  • サーバが提供する  復号化access token.

  • データを復号してユーザidを取得する.

  • useridを使用して、データベースでユーザーの権限を検証します.

  • ユーザーは、リクエストを処理するのに十分な権限を持っています.

  • ユーザに権限がない場合は、Unautorzed Response(401)または他のエラーコードが送信される.