開発のためにフロントエンドとバックエンドが分離されているのに、なぜユーザー認証が必要なのですか?その理由は、HTTPプロトコルが状態(ステートレス)を保存しないためです。つまり、アカウントパスワードを使用してユーザーを認証すると、次のリクエストの直前にデータが忘れられます。したがって、私たちのプログラムは誰が誰であるかを知らないので、もう一度確認する必要があります。したがって、システムのセキュリティを確保するには、ユーザーがログインしているかどうかを確認する必要があります。
1.従来の方法
Restful APIを介したデータ対話のためにフロントエンドとバックエンドが分離されている場合に、ユーザーのログイン情報とアクセス許可を確認する方法。元のプロジェクトでは、最も伝統的で単純な方法が使用されます。フロントエンドログイン、バックエンドはユーザー情報に基づいてトークンを生成し、トークンと対応するユーザーIDをデータベースまたはセッションに保存してから、トークンをユーザーに渡します。 、ブラウザのCookieに保存すると、ブラウザはこのCookieの取得を要求し、バックエンドはCookieの値に基づいてユーザーにクエリを実行し、有効期限が切れているかどうかを確認します。
しかし、これには多くの問題があります。ページにXSSの脆弱性がある場合、CookieはJavaScriptで読み取ることができるため、XSSの脆弱性によりユーザートークンがリークされ、ユーザーのIDを識別するバックエンドとして、Cookieのリークはユーザー情報がなくなったことを意味します。安全性。出力コンテンツをエスケープして[CDN](https://cloud.tencent.com/product/cdn?from=10680)などを使用することで、XSSインジェクションを回避できますが、大規模なプロジェクトでこの問題が発生しないことを保証することはできません。
Cookieを設定する場合、実際にはhttpOnlyとセキュアアイテムを設定できます。 httpOnlyを設定すると、JSはCookieを読み取れなくなり、ブラウザが自動的にリクエストヘッダーに追加します。セキュアが設定されている場合、CookieはHTTPS経由でのみ送信できます。セキュアオプションは、HTTPプロトコルを使用する一部のXSSインジェクションを除外できますが、完全に防止することはできません。
httpOnlyオプションを使用すると、JSはCookieを読み取れなくなるため、基本的にXSSインジェクションの問題について心配する必要はありません。ただし、httpOnlyを設定すると、別の問題が発生します。つまり、XSRFによって簡単に偽造される可能性があります。つまり、クロスサイトリクエストです。このページをブラウザで開くと、別のページがこのページのコンテンツを簡単にクロスサイトリクエストできます。デフォルトではCookieが送信されるためです。
さらに、検証情報がデータベースに保存されている場合、バックエンドは毎回トークンに基づいてユーザーIDを見つける必要があるため、データベースのクエリとストレージのオーバーヘッドが増加します。認証情報がセッションに保存されると、サーバー側の保存圧力が高まります。では、サーバーにクエリを実行することはできませんか?たとえば、対称暗号化アルゴリズムを使用してユーザーIDを暗号化してトークンを形成するなど、特定のルールに従ってトークンを生成する場合、サーバーはトークンを復号化することでユーザーIDが何であるかを実際に知ることができます。ただし、例を挙げます。これを行うと、対称暗号化アルゴリズムがリークされている限り、他の人がこの暗号化方法を使用してトークンを偽造でき、すべてのユーザー情報が安全ではなくなります。さて、非対称暗号化アルゴリズムでそれを行います。実際、これを行う仕様があります。これは、次に紹介するJWTです。
2. Json Webトークン(JWT)
WTはオープンスタンダード(RFC 7519)であり、通信する当事者間でJSONオブジェクトの形式で情報を安全に送信するための簡潔な自己完結型の方法を定義しています。 JWTは、HMACアルゴリズムまたはRSA公開キーキーペアを使用して署名できます。これには2つの特徴があります。
データ量が少なく、伝送速度が速いため、URL、POSTパラメータ、HTTPヘッダーで送信できます。
ロードにはすべてのユーザーが必要とする情報が含まれているため、データベースへの複数のクエリを回避できます
JWT構成
ヘッダ
ヘッダーには、トークンタイプと使用される暗号化アルゴリズムの2つの部分が含まれています
{" alg":"HS256","typ":"JWT"}
Base64エンコーディングを使用してJWT構造の最初の部分を形成します。Node.jsを使用する場合は、Node.jsパッケージbase64urlを使用してこの文字列を取得できます。
———— Base64はエンコーディングです。つまり、元の外観に戻すことができます。暗号化プロセスではありません。
ペイロード
負荷は、効果的な情報が保存される場所です。この効果的な情報は、次の3つの部分で構成されています。
-標準の登録ステートメント
---公式声明
---プライベートステートメント
公式声明:
公式声明では、あらゆる情報を追加できます。通常、ユーザー関連情報やビジネスに必要なその他の必要な情報を追加します。ただし、この部分はクライアントで復号化できるため、機密情報を追加することはお勧めしません。
プライベートステートメント:
プライベートステートメントは、プロバイダーとコンシューマーが共同で定義するステートメントです。base64は対称的に復号化されるため、機密情報を保存することは一般的に推奨されません。つまり、情報のこの部分はプレーンテキスト情報として分類できます。
{" iss":"lion1ou JWT","iat":1441593502,"exp":1441594722,"aud":"www.example.com","sub":"[email protected]"}//送信する必要のあるユーザー情報を含みます。{"iss":"Online JWT Builder","iat":1416797419,"exp":1448333419,"aud":"www.gusibi.com","sub":"uid","nickname":"goodspeed","username":"goodspeed","scopes":["admin","user"]}
その他が含まれます:
最初の2つの部分はすべてBase64を使用してエンコードされます。つまり、フロントエンドはロックを解除して内部の情報を知ることができます。署名では、エンコードされたヘッダーとペイロード、および提供されたキーを使用してから、ヘッダーで指定された署名アルゴリズム(HS256)を使用して署名する必要があります。署名の機能は、JWTが改ざんされていないことを確認することです。
//algアルゴリズムと秘密鍵に従って暗号化することによって取得された署名文字列。//このセクションは最も重要な機密情報であり、サーバー側でのみ復号化できます。HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),
SECREATE_KEY
)
3つの部分が接続されてJWTになっています。次のようになります。長さは、暗号化アルゴリズムと秘密鍵に関連しているようです。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3ZmVmMTY0ZTU0YWY2NGZmYzUzZGJkNSIsInhzcmYiOiI0ZWE1YzUwOGE2NTY2ZTc2MjQwNTQzZjhmZWIwNmZkNDU3Nzc3YmUzOTU0OWM0MDE2NDM2YWZkYTY1ZDIzMzBlIiwiaWF0IjoxNDc2NDI3OTMzfQ.PA3QjeyZSUh7H0GfE0vJaKW4LjKJuC3dVLQiY4hii8s
実際、この時点で、HTTP要求は常にトークンを運ぶので、トークンが渡されて不要な帯域幅を占有すると考える人もいるかもしれません。そう思うなら、HTTP2を理解することができます。HTTP2はヘッダーを圧縮します。これもこの問題を解決すると思います。
署名の目的
署名の最後のステップは、実際にはヘッダーとペイロードのコンテンツに署名して、コンテンツが改ざんされないようにすることです。誰かがヘッダーとペイロードの内容をデコード後に変更し、それをエンコードし、最後に前の署名の組み合わせを追加して新しいJWTを形成すると、サーバーは新しいヘッダーとペイロードによって形成された署名がJWTに添付されていると判断します。署名が異なります。新しいヘッダーとペイロードに署名する場合、サーバーの暗号化に使用されるキーがわからなくても、取得される署名も異なります。
情報開示
誰もが間違いなくここで質問するでしょう:Base64は一種のエンコーディングであり、リバーシブルです、そして私の情報は公開されますか?
はい。したがって、JWTでは、機密データを負荷に追加しないでください。上記の例では、ユーザーのユーザーIDを送信しています。この値は実際には敏感ではなく、通常の状況では安全に知ることができます。ただし、パスワードなどのコンテンツをJWTに配置することはできません。ユーザーのパスワードをJWTに入力すると、悪意のあるサードパーティがBase64デコードを介してパスワードをすばやく知ることができます。
したがって、JWTは、機密性の低い情報をWebアプリケーションに配信するのに適しています。 JWTは、ユーザー認証および承認システムの設計、さらにはWebアプリケーションのシングルサインオンの実装にもよく使用されます。
トークンが生成された後、トークンを使用してサーバーと通信できます。
3、JWTの使用
次の図は、JWTを使用したクライアントとサーバー間の対話プロセスを示しています。
ここでは、3番目のステップでJWTを取得した後、JWTをクライアントに保存し、認証を必要とするすべての要求にJWTを送信する必要があります。 (リクエスト時にヘッダーの承認に入れることができます)
まず、フロントエンドはユーザー名とパスワードをWebフォームを介してバックエンドインターフェイスに送信します。このプロセスは通常、HTTPPOSTリクエストです。推奨される方法は、SSL暗号化送信(httpsプロトコル)を使用して、機密情報が盗聴されるのを防ぐことです。
バックエンドはユーザー名とパスワードを正常にチェックした後、ユーザーのIDとその他の情報をJWTペイロード(ペイロード)として使用します。JWTペイロードはそれぞれBase64でエンコードされ、ヘッダーとスプライスされてJWTを形成します。結果のJWTは、lll.zzz.xxxに似た文字列です。
バックエンドは、フロントエンドへのログインが成功した結果としてJWT文字列を返します。フロントエンドは返された結果をlocalStorageまたはsessionStorageに保存でき、フロントエンドはログアウト時に保存されたJWTを削除できます。
フロントエンドは、要求するたびにJWTをHTTPヘッダーのAuthorizationビットに配置します。 (XSSおよびXSRFの問題を解決します)
バックエンドは、それが存在するかどうかをチェックし、存在する場合はJWTの有効性を検証します。たとえば、署名が正しいかどうか、トークンの有効期限が切れているかどうか、トークンの受信者が自分自身であるかどうかを確認します(オプション)。
検証に合格すると、バックエンドはJWTに含まれているユーザー情報を使用して他の論理操作を実行し、対応する結果を返します。
4、JWTの使用シナリオ
WTの主な利点は、アプリケーションのユーザーセッションをステートレスでスケーラブルな方法で処理できることです。サーバーは、ユーザーまたはセッションデータベースにアクセスすることなく、埋め込まれた宣言情報を通じてユーザーのセッション情報を簡単に取得できます。これは、分散サービス指向のフレームワークで非常に役立ちます。
ただし、システムがブラックリストを使用して長期的に効果的なトークン更新メカニズムを実装する必要がある場合、このステートレス性の利点は明らかではありません。
利点
急速な発展
クッキーは必要ありません
モバイルでのJSONの幅広いアプリケーション
ソーシャルログインに依存しません
比較的単純な概念的理解
不利益
トークンには長さ制限があります
トークンを取り消すことはできません
トークンに有効期限(exp)が必要
5、IDストレージとセッションモードの違い
セッションモードでユーザーIDを保存することの最大の欠点は、セッションがサーバー側に保存されるため、サーバーメモリを大量に消費し、大規模なアプリケーションの場合、多くの状態を保存する必要があることです。一般的に、大規模なアプリケーションでは、セッションストレージを実装するために、いくつかのKVデータベースと一連のキャッシュメカニズムを使用する必要もあります。
JWTメソッドは、ユーザーの状態をクライアントに配布します。これにより、サーバーのメモリ負荷を大幅に減らすことができます。ユーザーIDに加えて、ユーザーが管理者であるかどうか、ユーザーがいるグループなど、他のユーザー関連情報も保存できます。 JWT方式では、サーバーに計算上のプレッシャー(暗号化、エンコード、デコードなど)がかかりますが、これらのプレッシャーはディスクストレージと比較して何もありません。それを使用するかどうかにかかわらず、さまざまなシナリオで話すためにデータを使用する必要があります。
サインイン
セッション方式は、ユーザーIDを格納するために使用されます。最初は、ユーザーのセッションは1つのサーバーにのみ格納されます。複数のサブドメインを持つサイトの場合、各サブドメインは少なくとも1つの異なるサーバーに対応します(例:www.taobao.com、nv.taobao.com、nz.taobao.com、login.taobao.com)。したがって、login.taobao.comにログインした後でも、他のサブドメインでSessionを取得できることを認識したい場合は、複数のサーバーでSessionを同期する必要があります。ユーザーのステータスがクライアントに送信されているため、JWTを使用してもこの問題は発生しません。
6、要約
JWTの主な機能は次のとおりです。
(1)ユーザー情報を添付でき、バックエンドはJWTを介して直接関連情報を取得できます。
(2)ローカルストレージを使用し、HTTPヘッダーのAuthorizationビットを介して検証のために送信します。
**7つ、追加のpythonはJWT **を使用します
pythonのdjagnorestフレームワークでjwtを使用するには、次のモジュールを使用できます。githubsドキュメントに使用手順があります
https://github.com/GetBlimp/django-rest-framework-jwt
pip install djangorestframework-jwt
djangoを使用する代わりに、pyjwtを使用できます。
https://github.com/jpadilla/pyjwt/
使用する方が便利です。以下は、アプリケーションで使用した例です。
import jwt
import time
# 安らかなapiフレームワークとしてsanicを使用する
def create_token(request):
grant_type = request.json.get('grant_type')
username = request.json['username']
password = request.json['password']if grant_type =='password':
account =verify_password(username, password)
elif grant_type =='wxapp':
account =verify_wxapp(username, password)if not account:return{}
payload ={"iss":"gusibi.com","iat":int(time.time()),"exp":int(time.time())+86400*7,"aud":"www.gusibi.com","sub": account['_id'],"username": account['username'],"scopes":['open']}
token = jwt.encode(payload,'secret', algorithm='HS256')return True,{'access_token': token,'account_id': account['_id']}
def verify_bearer_token(token):
# トークンの生成時にaudパラメーターを使用する場合は、検証時にこのパラメーターも追加する必要があります。
payload = jwt.decode(token,'secret', audience='www.gusibi.com', algorithms=['HS256'])if payload:return True, token
return False, token
これまで、pythonでのJWTユーザー認証の実装に関するこの記事を紹介しました。関連するpython JWTユーザー認証の内容については、ZaLou.Cnの以前の記事を検索するか、次の関連記事を引き続き参照してください。今後、ZaLouをさらにサポートしていただければ幸いです。 Cn!
Recommended Posts