OAuthを使用したレガシーPHPビジネスアプリケーションのセキュリティー保護


アプリケーションはインターンで書かれることもあります.ときどきプロトタイプはプロダクションに入ります.時には残酷な古いアプリは、いくつかの“レガシー”と呼ばれる、他の人によって“マネーメーカー”と呼ばれています.FusionAuthのようなAuthシステムを導入すると、一般的にOIDC/OAuthで書かれていないアプリケーションでも、すべてのアプリケーションを使用したいと思います.
この2つの部分シリーズでは、代わりに近代的な認証システムを使用する独自のユーザーデータストアとビジネスPHPアプリケーションの行を更新します.第2部では、レガシーデータストアからFusionAuthにアカウントとプロファイルデータを移行する方法について学びます.
コードはすべて、FusionAuth GitHub repository それで、あなたはそれをクローン化することができて、あなたが好きであるならば、沿って続くことができます.

必要条件


あなたが行く前にいくつかのことを設定する必要があります.
  • FusionAuthの実行中のインスタンス.あなたがこれを持っていないならば、チェックしてください5 minute setup guide .
  • PHPの最新バージョン.このコードはPHP 7.3.11でテストされました.
  • ホームグロースAuthシステムでレガシーPHPアプリを導入する


    このポストがアップグレードする“偽”アプリケーションは認証システムを持っています.これには以下の問題があります.
  • 他のシステムとの統合は難しい.
  • それが働かない限り、誰もauthを気にかけません、そして、彼らが彼らの仕事をすることができないので、彼らは上下にジャンプします.
  • 世話とauthサブシステムの供給は、アプリケーションに機能を追加するから開発者を防ぐ.
  • しかし、それはあなたの会社そんなに多くのお金になるので、このアプリケーションを無視することはできません.実際には、それはそれはとても有利なので、“ATM”のニックネームを持っている.この偽のアプリケーションをチェックアウトすることによって表示することができますinsecure-legacy-app Githubレポの支店.また、view it online . 基本的に、インデックスページとサインインとサインアウトの方法があります.すべてのお金を稼ぐビジネスロジックは、それは、顧客や請求ベンダーを助ける在庫を更新するかどうかは、読者のための運動として残っている.
    このアプリケーションは、使用するのに十分な近代と仮定されてcomposer 多くの古いPHPアプリケーションがそのようなツールを使用しないにもかかわらず、依存関係を管理するために.このチュートリアルは徹底的ですが、現代の依存関係管理システムを使用するPHPアプリケーションの変換をカバーするのに十分徹底的ではありません.しかし、そのような道具に心を込めて約束を与えます.彼らはとても役に立つ.
    ここでは、このアプリケーションのエントリポイントです.index.php :
    <?php
    require __DIR__. '/config.php';
    require __DIR__. '/common.php';
    require __DIR__. '/vendor/autoload.php';
    ?>
    
    Welcome to the application.
    
    <?php if (!$_SESSION['user']) { ?>
    <?php if ($_SESSION['error']) { ?>
      <br/><span style="color: red;"><?php echo $_SESSION['error']; ?></span><br/>
    <?php } ?>
    <form action="/authenticate.php">
      Username: <input type="text" name="email"/> <br/>
      Password: <input type="password" name="password"/> <br/>
      <input type="submit" value="Log in"/>
    </form>
    <?php } ?>
    
    <?php if ($_SESSION['user']) { ?>
      You are logged in.<br/>
    
    <form action="/logout.php">
      <input type="submit" value="Log out"/>
    </form>
    <?php } ?>
    
    ユーザーがログインすると、authenticate.php 以下のようになります.
    <?php
    require __DIR__. '/config.php';
    require __DIR__. '/common.php';
    require __DIR__. '/vendor/autoload.php';
    
    if ($_REQUEST['email'] && $_REQUEST['password']) {
      if (auth($_REQUEST['email'], $_REQUEST['password'])) {
    
        // in reality, you'd load from a database
        $user = [];
        $user['email'] = $_REQUEST['email'];
        $user['favoriteColor'] = 'blue';
        $_SESSION['user'] = $user;
        unset($_SESSION['error']);
      } else {
        $_SESSION['error'] = 'Unable to authenticate';
      }
    }
    header("Location: /"); 
    ?>
    
    authenticate.php 呼び出しauth 関数は、ユーザが正しい資格情報を提供しているかどうかを判断します.通常、これはAuser テーブル、指定されたパスワードをハッシュし、格納されたハッシュと比較します.この偽のアプリケーションの場合は、単にパスワードを使用してpassword , 任意のユーザ名で.
    REPOをクローンする場合は、このようにアプリケーションを実行できます.
    php -S 0.0.0.0:8000
    
    訪問http://localhost:8000 アクションでこのアプリケーションを参照してください.ログインする前に、次のように表示されます.

    ログイン後、次のような画面が表示されます.

    さて、基本を見た今、先に進んで、アプリケーションを最新のAuthプロトコルを使用するように更新し始めましょう:OAuth.

    アプリケーションの設定


    FusionAuthでアプリケーションを構成し、レガシーPHPアプリケーションに対応する必要があります.ニックネームに対応するために「ATM」と呼びましょう.必要に応じて多くのアプリケーションとユーザーを持つことができます.
    管理ユーザーインターフェイスの「アプリケーション」に移動し、新しいものを作成します.OAuthタブに行き、「承認コード」グラントがチェックされることを確認してください.のリダイレクトURLを追加するhttp://localhost:8000/oauth-callback.php . 最後に、次のようになります.

    緑色の虫眼鏡を使用してアプリケーションを表示し、“OAuthの設定”セクションにスクロールします.注意Client ID and Client Secret 値、以下を使用します.

    アプリケーションを保存し、アプリケーションに登録されているユーザーを追加します.“ユーザー”に移動し、ユーザーを追加します.その後、“登録”タブに移動し、“ATM”のアプリケーションに登録するので、ログインして自分の仕事を続けることができます.

    最後に、テナント識別子が必要です.あなたがちょうどfusionauthをインストールするならば、1つのテナントがあります、しかし、FusionAuthはあなたが望む多くのテナントをサポートします.“テナント”に移動し、“default”テナントのIDをコピーします.
    それはfusionauthの設定のためのすべてです.それではPHPアプリケーションを見てみましょう.

    OAuthを使用して認証するPHPアプリの更新


    「ATM」PHPアプリケーションを更新するには、OAuthライブラリに依存を追加するために、作曲家を使用します.代わりにauthenticate.php ロジック、FusionAuthにリダイレクト.新しい流れの図です.
    許可コード付与データフロー.
    このセクションでは、変更を通過しますが、それらをチェックアウトすることによって見ることができますauth-with-oauth レポの支店.また、view it online . これらの変更は、ユーザーが承認されていることを確認するために承認コード付与を使用し、ユーザーデータを取得するためにOIDC終点を使用します.
    アップデートcomposer.json 以下のようにします.
    {
      "require": {
        "league/oauth2-client": "^2.5"
      }
    }
    
    これはaで引っ張りますwell supported PHP OAuth client library . このライブラリを使用すると、私と一緒に良い構成のいくつかの行にfusionauthとの統合を削減します.可能ならば常にライブラリを使用する良いアイデア.ジェネリックプロバイダーはうまく動作しますが、このライブラリにも他のカスタムプロバイダーがあります.
    新しい依存関係をインストールします
    composer install
    
    また、Aを設定する必要がありますconfig.php OAuthの秘密ファイルとテナント識別子を指定します.
    <?php
    
    // definitely update
    $client_id = '83767d78-2927-43fa-baef-b556d7c91c9a';
    $client_secret = 'a_pOJZu8D3Fy7a8fVxlPkVa92HPlnUt8d8JfJmtJL5U';
    $tenant_id = '30663132-6464-6665-3032-326466613934';
    
    // update if you aren't running the app or FusionAuth in the default location 
    $redirect_uri = 'http://localhost:8000/oauth-callback.php';
    $fa_url = 'http://localhost:9011';
    
    新しいindex.php ファイルは以下のようになります:
    <?php
    require __DIR__. '/config.php';
    require __DIR__. '/common.php';
    require __DIR__. '/vendor/autoload.php';
    
    $provider = new \League\OAuth2\Client\Provider\GenericProvider([
      'clientId' => $client_id, 
      'clientSecret' => $client_secret,
      'redirectUri' => $redirect_uri,
      'urlAuthorize' => $fa_url.'/oauth2/authorize',
      'urlAccessToken' => $fa_url.'/oauth2/token',
      'urlResourceOwnerDetails' => $fa_url.'/oauth2/userinfo' 
    ]);
    
    // Get the state generated for you and store it to the session.
    $_SESSION['oauth2state'] = $provider->getState();
    ?>
    
    Welcome to the application.
    
    <?php if (!$_SESSION['user']) { ?>
    <br/>
    <a href='<?php echo $provider->getAuthorizationUrl(); ?>'>Login</a>
    <?php } ?>
    
    <?php if ($_SESSION['user']) { ?>
      You are logged in.<br/>
    
      <form action="/logout.php">
        <input type="submit" value="Log out"/>
      </form>
    <?php } ?>
    
    この変更では、このアプリケーションをOAuthとOIDCを使用して残忍なローカルデータストアよりも認証を更新しました.全体authenticate.php ファイルは現在時代遅れです.内部のデータストアに投稿するのではなく、ユーザが「ログイン」をクリックしたときにfusionauthホストのログインページを指示します.これは彼らが見るものです(これはデフォルトのルックアンドフィールです)がthese pages can be themed ):

    認証後oauth-callback.php コードが実行されます.次のようになります.
    <?php
    require __DIR__. '/config.php';
    require __DIR__. '/common.php';
    require __DIR__. '/vendor/autoload.php';
    
    $provider = new \League\OAuth2\Client\Provider\GenericProvider([
      'clientId' => $client_id, 
      'clientSecret' => $client_secret,
      'redirectUri' => $redirect_uri,
      'urlAuthorize' => $fa_url.'/oauth2/authorize',
      'urlAccessToken' => $fa_url.'/oauth2/token',
      'urlResourceOwnerDetails' => $fa_url.'/oauth2/userinfo' 
    ]);
    
    if (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {
    
      if (isset($_SESSION['oauth2state'])) {
        unset($_SESSION['oauth2state']);
      }
    
      exit('Invalid state');
    }
    
    try {
    
      // Try to get an access token using the authorization code grant.
      $accessToken = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
      ]);
    
      // Using the access token, we may look up details about the
      // resource owner.
      $resourceOwner = $provider->getResourceOwner($accessToken);
      $_SESSION['user'] = $resourceOwner;
      header("Location: /"); 
    
    } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
    
      // Failed to get the access token or user details.
      exit($e->getMessage());
    
    }
    
    このコードはstate パラメータが変更されてからアクセストークン(通常はJSON Webトークン、またはJWT)を取得しますcode リクエストパラメータ.アクセストークンは、それからユーザーデータを返す終点に示される.それはセッションに格納されます、そして、ユーザーは上から変わらないインデックスページに戻されます.
    しかし、アプリケーションは、ユーザーが認証されている知っている.それにはuser 認証目的のためにチェックすることができるセッションのオブジェクト.また、ユーザーのロールに基づいてFusionAuthユーザーとアプリケーション機能へのコントロールへのアクセスを追加できます.

    次の手順


    それは素晴らしい、あなたは中央のデータストアを使用して、このアプリケーションを変換しました.あなたは集中的なソフトウェアパッケージに複雑さとセキュリティリスクの新しいユーザーとオフローディングの簡単な管理を含む集中Auth管理のすべての利点を得る.
    このフローは、新しいユーザーのために素晴らしい作品.しかし、どのように既存のユーザーをfusionauthに得るのですか?
    ああ、はい、それは重要です.重要なのは、完全に別の、今後のポストのトピックであること.