14

環境:

  • ジャワ
  • グラスフィッシュ
  • 別のマシンの REST サービス
  • AJAX と JQuery を使用した HTML5 クライアント
  • ジャージー

これは私がこれまでに実装したものです:

HTML5 クライアント

$('#btnSignIn').click(function () {
    var username = $("#username").val();
    var password = $("#password").val();

    function make_base_auth(user, password) {
        var tok = user + ':' + password;

        var final = "Basic " + $.base64.encode(tok);
        console.log("FINAL---->" + final);
        alert("FINAL---->" + final);

        return final;
    }

    $.ajax({
        type: "GET",
        contentType: "application/json",
        url: "http://localhost:8080/SesameService/webresources/users/secured/login",
        crossDomain: true,
        dataType: "text",
        async: false,
        data: {},
        beforeSend: function (xhr) {
            xhr.setRequestHeader('authorization', make_base_auth(username, password));
        },
        success: function () {
            alert('Thanks for your signin in! ');

        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(textStatus, errorThrown);
            alert(' Error in signIn-process!! ' + textStatus);
        }
    });
});

サーバ

セキュリティでは、セキュリティ マネージャーを有効にしていません。無効になっています。

Glassfish に BASIC 認証を設定しました。私の web.xml は次のようになります。

<servlet-mapping>
    <servlet-name>ServletAdaptor</servlet-name>
    <url-pattern>/webresources/*</url-pattern>
</servlet-mapping>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>REST Protected resources</web-resource-name>
        <description/>
        <url-pattern>/users/*</url-pattern>
        
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>customer</role-name>
        <role-name>user</role-name>
    </auth-constraint>
</security-constraint>



<login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>jdbcRealm</realm-name>
    </login-config>
    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>customer</role-name>
    </security-role>

グラスフィッシュ

ここに画像の説明を入力

ログ

FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/users/secured/login" "GET")
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
FINE: [Web-Security] hasResource isGranted: true
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/users/secured/login" "GET")

質問:

  1. ユーザーがサインアップするときにクライアントでパスワードを暗号化 (エンコードしない) し、SSL/HTTPS で転送する場合、これは安全で実装に適した方法ですか?

  2. クライアントなしで REST サービスを使用すると、常に開いているのはなぜですか? BASIC認証なし?これらの URL パターンに何か問題があることを理解しましたか?

     http://localhost:8080/SesameService/webresources/users/secured/login
    
  3. これが機能する場合、それをテストする方法は、一度認証すると常に承認されるためです。RESTサービス内でプログラムで「ログアウト」することは可能ですか、または一般的にログアウトを実装する方法はありますか?

  4. 必須のbase64でエンコードされたユーザー名:パスワードを含むヘッダーで承認を使用する場合、ユーザー名とパスワードもDBにエンコードする必要がありますか? 私はそれを試して、Glassfish の jdbcRealm に Encoding (許可されている値は Hex と Base64) を追加しました。パスワードで十分なようですが、両方がクライアントでエンコードされているとどうなりますか?

更新: web.xml を変更したところ、ブラウザーで REST サービスを直接呼び出すと、BASIC 認証が機能するようになりました。http://localhost:8080/SesameService/users/secured/login

変更点:

  • Glassfish でセキュリティ マネージャを有効にしました
  • URLパターンを変更しました
    <servlet-mapping>
        <servlet-name>ServletAdaptor</servlet-name>
        <url-pattern>/*</url-pattern>----> I took webresources off. It was generated by Netbeans
    </servlet-mapping>
  • サービスの URL を次のように変更しました。http://localhost:8080/SesameService/users/secured/login

HTML5 クライアントから認証しようとすると、HTTP/1.1 401 Unauthorized が返されます。

リクエスト ヘッダー:

Origin: http://localhost:8383
Host:localhost:8080
Connection:keep-alive
Access-Control-Request-Method:GET
Access-Control-Request-Headers:authorization,content-type

応答:

x-powered-by:Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.2.2 Java/Oracle Corporation/1.7)
WWW-Authenticate:Basic realm="jdbcRealm"
Server:GlassFish Server Open Source Edition 3.1.2.2
Pragma:No-cache
Expires:Thu, 01 Jan 1970 02:00:00 EET
Date:Sat, 13 Apr 2013 15:25:06 GMT
Content-Type:text/html
Content-Length:1073
Cache-Control:no-cache

更新 2

JavaScript + Authorization-header で認証しようとすると、401 エラーが発生し、ログに次のように記録されます。

FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/users/secured/login" "OPTIONS")
FINE: [Web-Security] hasUserDataPermission isGranted: true---->!!!!!!!!!!!!!
FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
FINE: [Web-Security] Codesource with Web URL: file:/SesameService/SesameService
FINE: [Web-Security] Checking Web Permission with Principals : null------->!!!!!!!
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
FINEST: JACC Policy Provider: PolicyWrapper.implies, context (SesameService/SesameService)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS"))
FINE: [Web-Security] hasResource isGranted: false------->!!!!!!!!!
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
FINEST: JACC Policy Provider: PolicyWrapper.getPermissions(cs), context (null) codesource ((null <no signer certificates>)) permissions: java.security.Permissions@5d4de3b0 (

更新 3 クロスドメインのケースで BASIC を使用して認証しようとしているのは、私だけではありません。クロス オリジン フィルターを次のように変更しました。

response.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Authorization");

401 エラーはなくなりましたが、JavaScript ではまだエラーです。IN Glassfish ログ:

FINEST: JACC Policy Provider:
getPolicy (SesameService/SesameService) is NOT in service----->!!!!!!!!
FINE: JACC Policy Provider: file arrival check type: granted  arrived: false exists: false lastModified: 0 storedTime: 1365968416000 state: deleted SesameService/SesameService
FINE: JACC Policy Provider: file arrival check type: excluded  arrived: false exists: false lastModified: 0 storedTime: 0 state: deleted SesameService/SesameService
FINE: TM: getTransaction: tx=null, tm=null
FINE: TM: componentDestroyedorg.apache.catalina.servlets.DefaultServlet@227fe9a8
FINE: TM: resourceTable before: 0
FINE: TM: resourceTable after: 0

ところで、私はこの作業をしたことがないので、独自のドメインで REST サービスを直接呼び出すのと同じ方法でこの作業を行います。最初にクライアント要求、サーバー要求、およびユーザー名とパスワードのウィンドウが開き、次にクライアント要求とサーバーがページを認証して応答しますか? 私はそれを取得しようとしています: Authorization ヘッダーを含むリクエスト、残りのサービスからの結果を含むサーバーからの応答、それだけです。RESTサービスを保護する方法はありますか? それより簡単ですか?不可能だよ。

更新 4

HTML5クライアントをJava Webプロジェクトの下、純粋なhtmlページだけで同じドメインの下に移動しようとしましたが、BASIC認証は100%機能しています。その理由は、クロスドメイン環境のためです。

4

2 に答える 2

10

ユーザーがサインアップし、SSL/HTTPS で転送するときにクライアントでパスワードを暗号化する (エンコードしない) 場合、これは安全で実装に適した方法ですか?

ほとんどの場合、SSL/HTTPS を介してプレーン テキストでパスワードを渡す必要があります。

SSL/HTTPS でのすべての通信は暗号化されるため、Web サーバー (技術的には HTTPS ターミネーター) がパスワードを認識できないようにする必要がない限り、パスワードも暗号化することはお勧めできません。

クライアントなしで REST サービスを使用すると、常に開いているのはなぜですか? BASIC認証なし?これらの URL パターンに何か問題があることを理解しましたか?

質問を理解しているかどうかわかりません。ただし、BASIC 認証はパスワードをプレーン テキストで渡すため、REST での認証には適していません。

これが機能する場合、それをテストする方法は、一度認証すると常に承認されるためです。RESTサービス内でプログラムで「ログアウト」することは可能ですか、または一般的にログアウトを実装する方法はありますか?

Basic 認証では、ユーザー名とパスワードはすべての HTTP リクエストでクライアントから渡されます。クレデンシャルがクライアントから渡されない場合、サーバーはリクエストを拒否します。そのため、セッションの概念はありません。

ただし、Java EE サーバーに関する限り、ログインによってユーザー セッションが作成され、同じユーザーによる今後の要求では同じセッションが使用されます。そのように構成すると、このセッションはタイムアウトになります。

ログアウトが重要な場合 (つまり、ユーザー セッションを制御する場合)、HTTP セッションを無効にするサーブレット (/logout) を作成する必要があります。

標準の Java セキュリティ モデルは次のように機能します。ユーザーがセキュリティ レルムにログインすると、Java EE サーバーは安全な Cookie をブラウザに保存します。ブラウザーは、同じレルムへの各要求で、この Cookie を Java EE サーバーに送り返します。Java EE サーバーは、すべての要求でこの Cookie をチェックし、それを使用してユーザーを識別し、要求をユーザーのセッションに接続します。

したがって、ブラウザとサーバーがシームレスに動作するように、REST サービスを Web アプリケーションと同じセキュリティ レルムに配置する必要があります。

base64 でエンコードされた必須のユーザー名:パスワードを含むヘッダーで Authorization を使用する場合、ユーザー名とパスワードも DB にエンコードする必要がありますか? 私はそれを試してみて、Glassfish の jdbcRealm に Encoding (許可されている値は Hex と Base64) を追加しました。パスワードで十分なようですが、両方がクライアントでエンコードされているとどうなりますか?

いいえ、ユーザー名やパスワードをエンコードしないでください。これはすべて、ブラウザーと Glassfish の奥深くで処理されます。クライアントでエンコードする場合、クライアントはエンコードをエンコードし、サーバーはパスワードを拒否します。


javaScript で html5 ページから j_security_check を使用することが可能かどうか教えてください。これは私にとって完全に災害のケースでした。

RESTful サービスが同じドメインとセキュリティ レルムにあると仮定すると、j_security_check を使用してこれを問題なく動作させることができるはずです (その後、Web アプリケーションにログオンすると、ブラウザは正しい Cookie を REST URI に送信できるようになります)。

ただし、他のアプリケーションでは REST サービスへのアクセスが困難になることに注意してください。基本的に、j_security_check 経由でログインし、Glassfish から送信された Cookie を維持する必要があります。これらのサービスにプログラムでアクセスするために他のアプリケーションが必要な場合は、別のソリューションが必要になります。

  1. さまざまなオーセンティケータが「十分」になるようにセキュリティ レルムを設定できます。HTTP BASIC Authもセットアップし、どれも「必要」とマークされていないことを確認してください
  2. RESTful サービスを 2 回デプロイします。もう 1 回は別の URI です。HTTP BASIC Auth を使用する場合は、パスワードが安全に処理されるように SSL/HTTPS エンドポイントになる可能性があります。
于 2013-04-15T04:44:43.547 に答える
0



私はSpring Securityを備えたSpring MVCフレームワークに取り組んでおり、基本認証を使用しています:

基本的に、HTTP 基本認証では、ユーザー名とパスワードは Base64 クラス (util パッケージから) を使用してキーまたはアクセス トークンに変換されます。

そして、そのキーは HTTP URL のヘッダーに設定され、サーバーにヒットします。

サーバーで正常に動作します。同じBase64でユーザー名パスワードキーをデコードし、データベースのユーザー名とパスワードと照合します。認証が完了したら、さらに処理します。

これにより、API URL の安全性が確保されます。誰もが簡単にアクセスできません。

コード: アクセス トークン (キー) の作成コードは次のとおりです。

注: エンコードのために Base64 (util パッケージから) "YourUsername:YourPassword" で文字列を渡します。
はい、ユーザー名とパスワードは「:」で区切られています。

        String encodeddata = new String(Base64.encodeBase64("username:password".getBytes()));
        System.out.println("encodedBytes " + encodeddata);

キーをヘッダーに設定するコード:

//キー付き URL へのリクエスト

        HttpClient client = HttpClientBuilder.create().build();
        HttpGet get = new HttpGet("http://google.com/Abc/api/vou/redeemed");
        get.setHeader("Authorization", "Basic "+encodeddata); //key getting above

注: これは、Get メソッドと Post メソッドの両方で使用できます。ここでは get メソッドのみを使用しています。//応答

        HttpResponse jresponse = client.execute(get);

        System.out.println("Response Code : "+ jresponse.getStatusLine().getStatusCode());

        BufferedReader rd = new BufferedReader(new InputStreamReader(jresponse.getEntity().getContent()));

        StringBuffer result = new StringBuffer();
        String line = "";
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }

        System.out.println("------Response is ::: "+ result);

//デコードキー

        String usernameAndPassword = null;
        try {
            usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword));
        } catch (Exception e) {
            System.out.println("SERVER_ERROR");
        }
        System.out.println(usernameAndPassword);

        final StringTokenizer tokenizer = new StringTokenizer(encodedUserPassword, ":");
        final String username = tokenizer.nextToken();
        final String password = tokenizer.nextToken();

        System.out.println(username);
        System.out.println(password);
于 2016-09-28T11:06:18.163 に答える