0

iPad クライアントを駆動するバックエンドと通信するためのライブラリを構築しています。

すべてのリクエストの基本構造は次のとおりです。

{
    "metaData":{ JSON Object that is not important for this question },
    "requestData":
        {
            "nonce":"random string",
            "params":"JSON string containing request data"
        }
     "checksum":"hash of JSON string representing value of requestData",
     "connectionString":"someIdentifier"
}

私が問題を抱えている特定のケースは、requestData が次の構造を持っている場合です。

{
    "requestData":
        {
            "nonce":"random string",
            "params":
                "{\"userId\":1,\"formData\":\"encrypted string, then Base 64 encoded on iPad\"}"
        }
    "checksum":"hashed value of string representation of requestData"
}

NSLogチェックサムの生成に使用される文字列 ( で表示) の例は次のとおりです。

{"params":"{\"groupId\":3,\"formData\":\"SExvR0J1ZkJSQkhObU5xZkiEXdBede2moVN3LtMDZlxcXYVj7Uz!BFdiQC9SwxIhrrcGv2GtWJzjqMhHzdFDZW568tbnLTKQ9931efrpjtvqlK9mudInXj0FQdBLY0M6f9zBlLu6TcQ7sA6AD15DF0HyUPIi4fnc90ZV7omGqRpyI412aGSpDPJEbCUBSY5WMUFJqRstyK1+Qo0vmN8uMprztDIyEFufP24DHHtYZHVAic8Sg8CxbsUTTYDgDc!0ASQwahEgy1sWkMP!BVpK8VU7quXDdIJrxbSNL7OO4tsJrHIXyhhK7ZUNKMaZX+fBSdw6DbNtTM86K0X4NSRXPVLE0EAklAJ2OpMDBsoz9k!jhCba5gRXY7r48USpsMyyj1v8SsDKn58FsvDxsdCrPY77KmIX3Icy!n3iA!lBfc3ol6c90wkwPSqNvnO7uRDYrfbP1c0zRYSXbLTQvHLLdfAWKariCKtNg6YAXNfgQ6lWFRXce8flHgUz6E7rkt9tjc9i4K+EjcL10H+E3AGkidYPGtQOm1vey!M8oineM!Cgg3VcvNCv!yN90iq3T+tqI0ivvBnh+1aCw2H90tnNm8Gi+XCrIdhORN3QjSkkNbpfoSCLoIkuBmXlNuTskaJ4nnV3kHrmU!4hYMeZIIZ8OnZWPpU47xJi!kh3MDdI2c+WorT+y+M5XwcQO6jGv3tXyRVBy!ne+sSnU!InISm7x1VQjJLmjULMnqxRDoZatBsofxICJysEUaDJvgwZasMJpQk1zyrPraBWBJ0lVVaWhH5OTi6U0!hHNVs5Xf+H23JxmPpUNWqNvsAGfnTfY!kSoiLoSxEocICK8zsJFMc69101DNAanayf!MjFFDeFRlzpKhcRON7cxDfvBdSoc9hL1lcMzFbLemrL1w8jNNMfKlY7QDZ5ebOERJMjY0!o8znlxOa0ViuJ++O7+QrT!mGdSQYGh3NJ3MK1IdJkXuFpY!guyXOgohTsqcD0DZSk84OsI76L18snFvs4qMHw9SUf3l0jWPxbTYimmlM3DVUR7Sn7xOsGmQGcwpGK1tinlIDA+w8Ci+CLWESsjZ5QDQCr\",\"internalFormId\":\"MTN13511759141\",\"userId\":1,\"code\":\"\",\"_queuedSubmission\":false,\"groupName\":\"LDMAdmin\",\"saleType\":\"1\",\"formTableName\":\"myTableName\",\"emailName\":\"default\"}","nonce":"XqfK9Nxwuggw4m"}

サーバー ログを調べると、デバイスで生成されたチェックサムがサーバーで生成されたチェックサムと一致しないことがわかりました (PHP では、大文字と小文字の区別は問題ではありません)。したがって、認証は失敗します。

失敗する構造の例は次のとおりです。

PageManager.m - 905 -> Final Request:
{
    "checksum":"9D51170D1510C4081936870D11E96C869DB26B895393B9C14B2A6BC3C1F10F23",
    "connectionString":"testBed",
    "metaData":
        {
            "accessToken":"myAccessToken",
            "appId":"myAppID",
            "deviceId":"1X:1X:1X:1X:1X:1X",
            "groupId":3,
            "groupName":"LDMAdmin",
            "timestamp":1351018002.780379,
            "userId":1,
            "useragent":"iPhone OS",
            "username":"admin"
        },
    "requestData":
        {
            "nonce":"1iezcBdjbE",
            "params":"{\"groupId\":3,\"formData\":\"Tnh3dWdndzRtRmdxSFNmN/NXCIQSukpx3+mhmbNQh0PTGbLlEFoDinyrq3wRJGZ+8sQ/+xcjS4cU7evluipxqQDZIOvp4ZcoDnxTPeqBZJrG/bq5FHR6PVCYK2DaLHfj025z/H3RM8dUEoWcrTLqSUcW+E7Mfl8ZCApqJMxSa8eYYqLT7tm7r1SC+bjXNOQZLTC2laFhihQ5hLKqFFnO/z3AlUYAAUhKKD1lWIipnJUUNoyHdWuuOobMSS1ZZP5f5f+RTFsmGZUDe6qX6h2cjIQ2+VGPIsP//gqwO4iDx/FdHD+xrjCyEgL2Va/m/Z+ANxCr3DN2o2Jnwg8B8QycFN2tGrgusseAgoa9Ng9LRgooZW+KuECWDhorHzvuv2rOlhOskymj4XTu8890ZMJbcr1Ic6zwztm82R1qKaoy1o6gIbUNtVZFSqUlP8TO7mWHKr3Y8Awn7ih9HzSOg1486EDL4OjfOR9J2pw1jbK7ZJb7LxzrWFgoyrwDBAw3q7PrV4Ml9ngI6oXOh3veAq/wulyBOdF46n7evqIkAKg4FYdvzmFKd2bgOpxwBlAI7vL2IiC4v8GXI5977SkPPEKUZHXWmfrgr/VzF79gIxJDqV9N0ceAcgY8bWbBXf7DLd9H82obFa60yZBo5/MBjq9SNuD08vJEEauVGs4wfDr9+xzsr3z+plqxAejODdxKfF48Ra21L8Xozozv5papTP9cpGVU11mCWj+no5gtM0VQKRB7IQcpDWjQgQyThN2aoE06ecA2gY5SSXN0XHVRw5OKM0/rlNIuMiqow5wqHLl41IzDSF2HuJKj06Lv8t5CLLOd9rkOjYw6w8SrbsZeG5jwagJkyQ0UuKu+PIoIc2DJnUWDC5iqlb0TO9nPDNFKad+MYlfgDR0CxR+3ddkqWNBNSW5rsh5QZDlJHDjhQFLkuqiiRAnMvKOcbqAnXIZ9EuAo/DkcmtGPHkEyEaA2cb3mXysBP49jhY0m/qinloza+j3d7Kb/Fu35U929fOxH6+W+5oZv/r+a9KvkDhPoRwiFouVwTtTOwbjVDT+NEg2OUfDaEYbQ/RbM7i6X+XjSkZMLYsRs1Q9CwdBabY860uBNFQ==\",\"internalFormId\":\"MTN13510178111\",\"userId\":1,\"code\":\"\",\"_queuedSubmission\":false,\"groupName\":\"LDMAdmin\",\"saleType\":\"1\",\"formTableName\":\"myTableName\",\"emailName\":\"default\"}"
        },
    "url":"http://myurl.com/myAction"
}

は、目的のデータの文字列をformData作成し、JSONこの文字列を暗号化し、結果のNSDataオブジェクトを Base 64 文字列にエンコードすることによって生成されます。は、値を表す文字列checksumのハッシュを取得することによって生成されます (SHA256 を使用)。JSONrequestData

requestDataJSON 文字列に変換され、次のようにハッシュされます。

+(NSString *)hmacSHA256:(NSString *)string withKey:(NSString *)key {
    NSString *hash = 0;
    NSData   *hmac = 0;

    NSMutableString *temp = [[NSMutableString alloc] initWithString:@""];

#ifdef DEBUG
    NSLog( @"%s - %d -> Values:\nString:  %@\nKey:  %@", __FILE__, __LINE__, string, key );
#endif


    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [string cStringUsingEncoding:NSASCIIStringEncoding];

    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    unsigned char *digest;
    unsigned int  dLength;

    CCHmac( kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC );

    hmac = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];

    digest  = (unsigned char *)[hmac bytes];
    dLength = hmac.length;

    for ( int i = 0; i < dLength; ++i )
        [temp appendFormat:@"%02X", digest[i]];

    hash = [[NSString alloc] initWithString:temp];

    return hash;
}

PHP スクリプトは、ストック関数を使用してハッシュを生成します。

protected static function _generateChecksum($data, $key, $output)
    {
        $jsonData = json_encode($data);
        log_message('error', 'encoded string is: '.$jsonData);
        $checksum = hash_hmac('sha256', $jsonData, $key);
        //log_message('error', 'Checksum pre encode: '.$checksum);
        // if($output == true)
        // {
        //     $checksum = base64_encode($checksum);
        // }
        return $checksum;
    }

ハッシュは、リクエストで送信されたハッシュと比較されます。

サーバーログの例:

ERROR - 2012-10-23 21:31:16 --> Encoded Checksum recieved is: 14F03A1DCAEA9DBBC7EC8CA1D666D89C391760AA246C91B52164D526AC83E5E5
DEBUG - 2012-10-23 21:31:16 --> Model Class Initialized
DEBUG - 2012-10-23 21:31:16 --> Model Class Initialized
DEBUG - 2012-10-23 21:31:16 --> Database Driver Class Initialized
ERROR - 2012-10-23 21:31:16 --> encoded string is: {"params":"{\"groupId\":3,\"formData\":\"SE5tTnFmWHFmSzlOeHd1ZyYzHN9y\/aJSbsqEn6X1TypGwWcXtXGpW4ODrCDVwZyIjhq3oOeZ4C6hGCDFGqHsa5hhNXxeerWLG5SyvfksCTG1+GCvWFwMx0CzZwOAfJRwSoCBCaeZ\/pivs3dHQS22SEbWn6+2e2vayeap7mxvZZw9Jrl\/c4dGFAiNqQB5pQbNO661AqbJWDAHCS8EWBhXXsd0SbTHlZAip4H0MdlF2rnElCVfHlc01RcuJNXLF3NJvfjY9m4sXmI3BAED0c0C\/i0Uw2M6pe4iDJv\/OvOI0NVS8RKbRbjhTo3oktAmNttfKTG6xp0wMhbANppuoo4QY3XwQ5BKUjqhmr5kx8j0RTmebcTCmxsC9h1dqjHYnf1JnZDFATkVsKnn\/Ela1wSjhGL7uP6jl3r4xDGKGPWDj0E3iAPNN56pmJxzyQrHOOqUzGbmvU3qj7Ul039IGYZTzn74VUkWi3JsxJH+kU9iWSvuC+YoOHcf\/0OFn1PqBoDHjDTbN+3HV8wwSqrVFJ6z9RX4MwRfffVgKl8xL2hHqBnegjvyd65KbZbSd\/3OrEBeL0dAjuARiPioNTpjzwga4chFRA471gweLT+cKweZBXZMYll36sNqulIBzbCmqbndDk63Id9iSrs9\/fQVWUA7RJDudnAxvQPs8gTznp9Dz1SomyY4ONYrJ9EticAEnUEjF2sCdejYlgu61a3Zss19m+MzgEhxkwmRwttsRbFfNK44wP\/wB2FgdfjsY94nHpJ+6lPEZtRmWpYtNVxQMVC6mMde6CbSEem71byIiN424baPImtNIfF+bKl6BKxyEl7BhI3z25NXaKyfaflzxGY8Yvdg0f73SfT3omPP3KxdudFgJrQ6eiO2AXt5L6lPjezjRr17R6hTUNmYwvZ3C5S0zoY7ynmCHebeiNlavVepUBkn0Iu6w\/qKDJ5wr80n7XX3EXuo1ODCC5aCjOSr+gSS9eVm0\/IBQNF\/ec4kjI29LRyrOFOS\/2poHY9XzyagVURiwi101a0yPETRRsC8n4B\/XFmOFQ0VcCQNgTuXute52fsccxB3DkV7ixBbQ8mt6o2XDWGk2HnrDwmRuNX87rBHow==\",\"internalFormId\":\"MTNC13510277491\",\"userId\":1,\"code\":\"\",\"_queuedSubmission\":false,\"groupName\":\"LDMAdmin\",\"saleType\":\"1\",\"formTableName\":\"myTableName\",\"emailName\":\"default\"}","nonce":"gw4m"}
ERROR - 2012-10-23 21:31:16 --> Encoded Checksum expected is: 8d999d76e48907905e701da3ccdbccb4061d05ed5a7c18b58507b6e6352fb1f5

ただし、アプリケーションの他のコンポーネントは同じ構造を使用しており (base 64 エンコーディングを除く)、設計および期待どおりに動作します。はchecksum、上記の例と同じメソッドとキーを使用して生成されます。例:

{
    "requestData":
        {
            "nonce":"random string",
            "params":"{\"latitude\":37.7,\"longitude\":-122.4}"
        }
    "checksum":"hashed value of the string representation of requestData"
}

上記の失敗した場合に、サーバー上の PHP スクリプトが別のハッシュを生成する理由がわかりません。以前にこの種の問題に遭遇した人はいますか?

アップデート:

SBJsonデータ構造を JSON 文字列にエンコードおよびデコードするために使用しています ( link )。

更新 2:

これまでの議論に基づいて、JSON オブジェクト (または私の場合はNSDictionary) がJSON文字列にシリアル化される順序を保証するものではありません。しかし、そうであれば、データが平文で送信され、サーバー上で同じハッシュが生成され、一部のデータが base 64 文字列の形式である場合に別のハッシュが生成される理由がわかりません。サーバーとクライアントの間で生成されます。

おそらく正しい解決策ではない唯一の解決策は/、base 64 アルファベットから削除することです (私はそれを に置き換えました!)。サーバー側で文字列をデコードしようとすると、これが問題を引き起こすと確信しています。

この時点で、スラッシュがどのようにこの問題を引き起こしているのかを理解したいと思います。

4

2 に答える 2

0

「あれこれを表すJSON文字列」なんてものはありませんメモリ内にデータ構造があり、プラットフォームのデフォルトの JSON シリアライザーを使用する場合、別のプラットフォームのデフォルトの JSON シリアライザーと同じ文字列が生成されるという保証はなく、JSON シリアライザーと同じ文字列が生成されるという保証さえありません。明日、またはうるう年の金曜日に生成されます。

JSON を使用すると、空白を配置する場所、数値をフォーマットする方法、オブジェクト フィールドを出力する順序などについて、シリアライザーにかなりの自由度が与えられます。基になる抽象データセットをハッシュするための基礎として使用することはできません。

于 2012-10-23T21:39:55.323 に答える
0

エンコーディング テーブルにあったのはスラッシュで、どういうわけか、これが php コードでハッシュを生成するときに競合を引き起こしていました。

Objective C コードの元のテーブル:

//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

私が置き換えなければならなかったもの:

//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+!";

このSO 回答では、ベース 64 でエンコードされた文字列ではスラッシュを使用できると記載されているため、これは一時的な解決策にすぎない可能性があります。スラッシュを置き換えるだけで、今のところ問題は解決しました。

于 2012-10-24T16:31:56.620 に答える