如何使用 PHP 在我的“第三方服务器"上验证 GKLocalPlayer? [英] How to authenticate the GKLocalPlayer on my 'third party server' using PHP?

查看:27
本文介绍了如何使用 PHP 在我的“第三方服务器"上验证 GKLocalPlayer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请原谅我的笨拙,我是 Stackoverflow、C# 和 Objective C 的新手.

Please forgive my clumsiness, I'm new to Stackoverflow, C#, and Objective C.

简而言之,我正在尝试做这个问题中的回答,但在 PHP 中:如何在我的第三方服务器"上验证 GKLocalPlayer?希望这也能帮助其他从事相同工作的 PHP 开发人员.

In a nutshell, I'm trying to do what is answered in this question, but in PHP: How to authenticate the GKLocalPlayer on my 'third party server'? Hopefully this will also help other PHP devs working on the same thing.

我正在使用 Unity (Unity3D) 和 PHP 服务器端.我已经让 Objective C 正确连接到 GameCenter 并通过调用 generateIdentityVerificationSignatureWithCompletionHandler 返回数据.不幸的是,我无法弄清楚我在验证 SHA1 哈希时做错了什么.过去一周我一直在努力解决这个问题,尝试了各种方法,但没有成功.

I'm using Unity (Unity3D) and PHP server-side. I've got Objective C properly connecting to GameCenter and returning data via a call to generateIdentityVerificationSignatureWithCompletionHandler. Unfortunately, I can't figure out what I'm doing wrong to validate the SHA1 hash. I've been working on this for the past week, trying all sorts of things, but with no luck.

我正在尝试三种不同的方式来生成 SHA1 哈希(如下所示).一次在目标 C 中,另一个在 Unity 的 C# 中,最后第三次在我的服务器上使用 PHP.Objective C 和 C# SHA1 哈希最终相同.但是,PHP 与它们不匹配.并且没有一个通过 Apple 的公共证书和签名进行验证.

I'm trying three different ways of making the SHA1 hash (shown below). Once in Objective C, another in Unity's C#, and finally a third time on my server in PHP. The Objective C and C# SHA1 hashes end up identical. However, the PHP one does not match them. And none validate against Apple's public cert and signature.

诚然,我可能误解了一些基本的东西.至少要验证 Objective C 和 C# 哈希值将是一个巨大的进步.

Admittedly, I could be misunderstanding something fundamental. It would be a huge step to at least get the Objective C and C# hashes to validate.

谢谢.

目标 C 代码:

[localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) {
    NSDictionary *params = @{@"public_key_url": [publicKeyUrl absoluteString],
                             @"timestamp": [NSString stringWithFormat:@"%llu", timestamp],
                             @"signature": [signature base64EncodedStringWithOptions:0],
                             @"salt": [salt base64EncodedStringWithOptions:0],
                             @"player_id": [GKLocalPlayer localPlayer].playerID,
                             @"app_bundle_id": [[NSBundle mainBundle] bundleIdentifier]};
    //  Build hash using iOS...
    NSMutableData *payload = [[NSMutableData alloc] init];
    [payload appendData:[[GKLocalPlayer localPlayer].playerID dataUsingEncoding:NSASCIIStringEncoding]];
    [payload appendData:[[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding:NSASCIIStringEncoding]];
    uint64_t timestampBE = CFSwapInt64HostToBig(timestamp);
    [payload appendBytes:&timestampBE length:sizeof(timestampBE)];
    [payload appendData:salt];
    uint8_t sha1HashDigest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1([payload bytes], [payload length], sha1HashDigest);
    //  Convert to hex string so it can be sent to Unity's C# then to the PHP webserver...
    NSString *sIOSHash = [self stringFromDigest:sha1HashDigest length:CC_SHA1_DIGEST_LENGTH];
    //  END - Build hash using iOS

    //  Build string to send to Unity's C#...
    NSMutableString * data = [[NSMutableString alloc] init];
    [data appendString:params[@"public_key_url"]];
    [data appendString:@","];
    [data appendString:params[@"timestamp"]];
    [data appendString:@","];
    [data appendString:params[@"signature"]];
    [data appendString:@","];
    [data appendString:params[@"salt"]];
    [data appendString:@","];
    [data appendString:params[@"player_id"]];
    [data appendString:@","];
    [data appendString:params[@"app_bundle_id"]];
    [data appendString:@","];
    [data appendString:sIOSHash];
    //  END - Build string to send to Unity's C#.

    //  Send string to Unity's C# for parsing and sending off to PHP webserver.
    NSString *str = [[data copy] autorelease];
    UnitySendMessage("GameCenterManager", "onAuthenticateLocalPlayer", [ISNDataConvertor NSStringToChar:str]);
}];
//  Helper method to convert uint8_t into a hex string for sending to the webserver.
- (NSString *)stringFromDigest:(uint8_t *)digest length:(int)length {
    NSMutableString *ms = [[NSMutableString alloc] initWithCapacity:length * 2];
    for (int i = 0; i < length; i++) {
        [ms appendFormat: @"%02x", (int)digest[i]];
    }
    return [ms copy];
}

接下来是生成 SHA1 哈希的第二个版本的 C# 代码(在 Unity3D 中).这些变量都从 iOS 代码(上图)发送到 Unity,并以字符串形式出现:player_idapp_bundle_idtimestamp.(我没有显示任何要发送到我的服务器的 Unity3D C# 代码.但是我使用了 WWWFormAddField 来发送它.我也没有显示bridge" 将数据从 Objective C 移动到 C# 的代码.)

What follows is the C# code (within Unity3D) to generate the second version of the SHA1 hash. These variables are all sent to Unity from the iOS code (above), and came in as strings: player_id, app_bundle_id, timestamp, salt. (I'm not showing any Unity3D C# code to send to my server. But I'm using the WWWForm and AddField to send it. Nor am I showing the "bridge" code to move data from Objective C to C#.)

var sha1 = new SHA1Managed();
var data = new List<byte>();
data.AddRange(Encoding.UTF8.GetBytes(player_id));
data.AddRange(Encoding.UTF8.GetBytes(app_bundle_id));
data.AddRange(ToBigEndian(Convert.ToUInt64(timestamp)));
data.AddRange(Convert.FromBase64String(salt));
var sig = data.ToArray();
public static string CSharpHash = ToHex(sha1.ComputeHash(sig), false);

最后一个代码块是我的服务器端 PHP,它从客户端接收数据,验证公共证书,然后尝试根据它和签名验证哈希.最后一部分是我被卡住的地方.

This last code block is my server-side PHP that receives the data from the client, validates the public cert, and then tries to verify the hash against it and the signature. That last part is where I am stuck.

/*
Sample data as received within the PHP (all strings):
$public_cert_url    eg: https://sandbox.gc.apple.com/public-key/gc-sb.cer
$timestamp          eg: 00-00-01-47-12-9C-16-D4             [derived from: 1404766525140]
$signature          eg: EGc8J9D7SdZ0qq2xl2XLz2[lots more...]
$salt               eg: LDfyIQ==
$player_id          eg: G:[#########]
$app_bundle_id      eg: com.[mydomain].[myapp]

$sIOSHash           eg: 00032b9416315c8298b5a6e7f5d9dec71bd5ace2        [The C# and Objective C code both generate the same hash.]
$CSharpHash     eg: 00032b9416315c8298b5a6e7f5d9dec71bd5ace2
*/


//  Verify the public cert.
//  As far as I understand, PHP's openssl_pkey_get_public() cannot read raw 
//      cer data, so I download and convert to PEM. Optimize later.
$fp = fopen("temp.cer", "w");       //  Open file for writing.
$header[] = "Content-Type: application/pkix-cert";
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_URL, $public_cert_url);
curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_exec($curl);
curl_close($curl);
fclose($fp);
shell_exec("openssl x509 -inform der -in temp.cer -out temp.pem");  //  Convert to PEM.
$pub_cert = file_get_contents("temp.pem");
$sKey = openssl_pkey_get_public($pub_cert);     //  Validate PEM file here.
If( $sKey === False ) echo "pkey bad";
//  This ^^ works.


//  This is where I am stuck:

//  Verify the data from the client against the signature from the client 
//      and the downloaded public key.
//  First, try to verify against a hash created within PHP:
$iResult = openssl_verify(
        sha1($player_id . $app_bundle_id . $timestamp . $salt), 
        $signature, 
        $pub_cert, 
        OPENSSL_ALGO_SHA1);
If( $iResult != 1 ) echo "not valid PHP hash!
";

//  Second, see if it will verify by using the hash created in.
$iResult = openssl_verify($sIOSHash, $signature, $pub_cert, OPENSSL_ALGO_SHA1);
If( $iResult != 1 ) echo "not valid sIOSHash hash!
";

//  Finally, does the C# has verify?
$iResult = openssl_verify($CSharpHash, $signature, $pub_cert, OPENSSL_ALGO_SHA1);
If( $iResult != 1 ) echo "not valid CSharpHash hash!
";

//  None of these ^^ ever validate.   

更新:2014 年 7 月 9 日
我通过不对数据执行 SHA1 来验证数据.我对 Apple 文档感到困惑(https://developer.apple.com/library/prerelease/ios/documentation/GameKit/Reference/GKLocalPlayer_Ref/index.html#//apple_ref/occ/instm/GKLocalPlayer/generateIdentityVerificationSignatureWithCompletion/a>:).特别是#7,它说:为缓冲区生成一个 SHA-1 哈希值."

Update: Jul 9 2014
I got it to validate the data by not doing SHA1 on it. I was confused by the Apple documentation (https://developer.apple.com/library/prerelease/ios/documentation/GameKit/Reference/GKLocalPlayer_Ref/index.html#//apple_ref/occ/instm/GKLocalPlayer/generateIdentityVerificationSignatureWithCompletionHandler:). Specifically #7 which says: "Generate a SHA-1 hash value for the buffer."

我删除了所有 C# 代码(以尝试生成有效负载),现在只使用 Objective C.

I removed ALL the C# code (to try and generate the payload) and now only use the Objective C.

修改如下:

NSMutableData *payload = [[NSMutableData alloc] init];
[payload appendData:[[GKLocalPlayer localPlayer].playerID dataUsingEncoding:NSUTF8StringEncoding]];
[payload appendData:[[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding:NSUTF8StringEncoding]];
uint64_t timestampBE = CFSwapInt64HostToBig(timestamp);
[payload appendBytes:&timestampBE length:sizeof(timestampBE)];
[payload appendData:salt];
NSString *siOSData = [payload base64EncodedStringWithOptions:0];

注意删除 SHA1.

我放弃了在 PHP 中创建负载的尝试.我尝试了许多包、转换、将我的服务器升级到 64 位等变体.但我认为(如果我错了,请纠正我)因为我从客户端传输与构成有效载荷完全相同的数据,它应该没事.

I gave up on trying to create the payload in PHP. I tried many variations of pack, conversions, upgrading my server to 64 bit, etc. But I think (please correct me if I am wrong) that since I am transmitting the exact same data from the client as makes up the payload, it should be ok.

苹果注意事项:
请实施 OAuth 2.0.

Note to Apple:
PLEASE implement OAuth 2.0.

我还想出了如何验证 Apple cer 文件而不浪费处理保存到文件的方法.如下:

I also figured out how to validate the Apple cer file without wasting processing on saving to a file. As follows:

// Get data from client. I urlencoded it before sending. So need to urldecode now.
// The payload is in "iosdata" and it, along with the signature, both need to be
//  base64_decoded.
$sIOSData       = ( isset($_REQUEST["iosdata"]) ) ? urldecode(Trim($_REQUEST["iosdata"])) : "";
$sIOSData       = base64_decode($sIOSData);
$sSignature = ( isset($_REQUEST["signature"]) ) ? urldecode(Trim($_REQUEST["signature"])) : "";
$sSignature = base64_decode($sSignature);

// Here is where I download Apple's cert (DER format), save it as raw bits  
//  to a variable, convert it to PEM format (the ONLY format PHP's OpenSSL 
//  works with apparently...?) and then validate it.
// TODO: figure out if Apple live returns different results each time, and/or if
//  this can be cached. Apple sandbox returns the same each time.
$header[0] = "Content-Type: application/pkix-cert";
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_URL, $sPublicKeyUrl);
curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$der_data = curl_exec($curl);
curl_close($curl);
$sPublicKey = chunk_split(base64_encode($der_data), 64, "
");
$sPublicKey = "-----BEGIN CERTIFICATE-----
".$sPublicKey."-----END CERTIFICATE-----
";
$sKey = openssl_pkey_get_public($sPublicKey);
If( $sKey === False ) Return "pkey bad";

// Here I use the package ($sIOSData) and signature to validate against Apple's
//  public certificate.
$iResult = openssl_verify($sIOSData, $sSignature, $sKey, OPENSSL_ALGO_SHA1);
If( $iResult != 1 ) {
    echo "BAD!
";
    echo "error: ".openssl_error_string()."
";
}else{
    echo "WORKED!
";
}

欢迎反馈.我相信有很多事情可以改进.但希望这能帮助某人节省一周的工作时间.

Feedback is welcome. I'm sure there are tons of things that can be improved on. But hopefully this will help save someone a week of work.

推荐答案

我玩得很开心.Garraeth 的代码很有帮助,但还有一些其他有用的提示散布在 SO 周围,加上 php 文档,加上一些幸运的猜测,我终于得到了这个:

I had a heck of a time with this. Garraeth's code was helpful, but there were a few other helpful hints scattered around SO, plus the php docs, plus some lucky guessing, and I finally arrived at this:

在 iOS 方面:

主要验证用户代码:

// Don't bother verifying not-authenticated players
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if (localPlayer.authenticated)
{
    // __weak copy for use within code-block
    __weak GKLocalPlayer *useLocalPlayer = localPlayer;
    [useLocalPlayer generateIdentityVerificationSignatureWithCompletionHandler: ^(NSURL * _Nullable publicKeyUrl,
                                                                                  NSData * _Nullable signature,
                                                                                  NSData * _Nullable salt,
                                                                                  uint64_t timestamp,
                                                                                  NSError * _Nullable error) {

        if (error == nil)
        {
            [self verifyPlayer: useLocalPlayer.playerID // our verify routine: below
                  publicKeyUrl: publicKeyUrl
                     signature: signature
                          salt: salt
                     timestamp: timestamp];
        }
        else
        {
            // GameCenter returned an error; deal with it here.
        }
    }];
}
else
{
    // User is not authenticated; it makes no sense to try to verify them.
}

我的verifyPlayer:例程:

-(void)verifyPlayer: (NSString*) playerID
       publicKeyUrl: (NSURL*) publicKeyUrl
          signature: (NSData*) signature
               salt: (NSData*) salt
          timestamp: (uint64_t) timestamp
{
    NSDictionary *paramsDict = @{ @"publicKeyUrl": [publicKeyUrl absoluteString],
                                  @"timestamp"   : [NSString stringWithFormat: @"%llu", timestamp],
                                  @"signature"   : [signature base64EncodedStringWithOptions: 0],
                                  @"salt"        : [salt base64EncodedStringWithOptions: 0],
                                  @"playerID"    : playerID,
                                  @"bundleID"    : [[NSBundle mainBundle] bundleIdentifier]
                                  };

    // NOTE: A lot of the code below was cribbed from another SO answer for which I have lost the URL.
    // FIXME: <When found, insert other-SO-answer URL here>

    // build payload
    NSMutableData *payload = [NSMutableData new];
    [payload appendData: [playerID dataUsingEncoding: NSASCIIStringEncoding]];
    [payload appendData: [[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding: NSASCIIStringEncoding]];

    uint64_t timestampBE = CFSwapInt64HostToBig(timestamp);
    [payload appendBytes: &timestampBE length: sizeof(timestampBE)];
    [payload appendData: salt];

    // Verify with server
    [self verifyPlayerOnServer: payload withSignature: signature publicKeyURL: publicKeyUrl];

#if 0   // verify locally (for testing)

    //get certificate
    NSData *certificateData = [NSData dataWithContentsOfURL: publicKeyUrl];

    //sign
    SecCertificateRef certificateFromFile = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); // load the certificate
    SecPolicyRef secPolicy = SecPolicyCreateBasicX509();

    SecTrustRef trust;
    OSStatus statusTrust = SecTrustCreateWithCertificates(certificateFromFile, secPolicy, &trust);
    if (statusTrust != errSecSuccess)
    {
        NSLog(@"%s ***** Could not create trust certificate", __PRETTY_FUNCTION__);
        return;
    }

    SecTrustResultType resultType;
    OSStatus statusTrustEval =  SecTrustEvaluate(trust, &resultType);
    if (statusTrustEval != errSecSuccess)
    {
        NSLog(@"%s ***** Could not evaluate trust", __PRETTY_FUNCTION__);
        return;
    }

    if ((resultType != kSecTrustResultProceed)
    &&  (resultType != kSecTrustResultRecoverableTrustFailure) )
    {
        NSLog(@"%s ***** Server can not be trusted", __PRETTY_FUNCTION__);
        return;
    }

    SecKeyRef publicKey = SecTrustCopyPublicKey(trust);
    uint8_t sha256HashDigest[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256([payload bytes], (CC_LONG)[payload length], sha256HashDigest);

    NSLog(@"%s [DEBUG] sha256HashDigest: %@", __PRETTY_FUNCTION__, [NSData dataWithBytes: sha256HashDigest length: CC_SHA256_DIGEST_LENGTH]);

    //check to see if its a match
    OSStatus verficationResult = SecKeyRawVerify(publicKey,  kSecPaddingPKCS1SHA256, sha256HashDigest, CC_SHA256_DIGEST_LENGTH, [signature bytes], [signature length]);

    CFRelease(publicKey);
    CFRelease(trust);
    CFRelease(secPolicy);
    CFRelease(certificateFromFile);
    if (verficationResult == errSecSuccess)
    {
        NSLog(@"%s [DEBUG] Verified", __PRETTY_FUNCTION__);

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateGameCenterUI];
        });
    }
    else
    {
        NSLog(@"%s ***** Danger!!!", __PRETTY_FUNCTION__);
    }

#endif
}

我将代码传递给服务器的例程(摘自这个问题):

- (void) verifyPlayerOnServer: (NSData*) payload withSignature: signature publicKeyURL: (NSURL*) publicKeyUrl
{
    // hint courtesy of: http://stackoverflow.com/questions/24621839/how-to-authenticate-the-gklocalplayer-on-my-third-party-server-using-php
    NSDictionary *jsonDict = @{ @"data" : [payload base64EncodedStringWithOptions: 0] };

    //NSLog(@"%s [DEBUG] jsonDict: %@", __PRETTY_FUNCTION__, jsonDict);

    NSError *error = nil;
    NSData *bodyData = [NSJSONSerialization dataWithJSONObject: jsonDict options: 0 error: &error];

    if (error != nil)
    {
        NSLog(@"%s ***** dataWithJson error: %@", __PRETTY_FUNCTION__, error);
    }

    // To validate at server end:
    //  http://stackoverflow.com/questions/21570700/how-to-authenticate-game-center-user-from-3rd-party-node-js-server

    // NOTE: MFURLConnection is my subclass of NSURLConnection.
    // .. this routine just builds an NSMutableURLRequest, then
    // .. kicks it off, tracking a tag and calling back to delegate
    // .. when the request is complete.
    [MFURLConnection connectionWitURL: [self serverURLWithSuffix: @"gameCenter.php"]
                              headers: @{ @"Content-Type"   : @"application/json",
                                          @"Publickeyurl"   : [publicKeyUrl absoluteString],
                                          @"Signature"      : [signature base64EncodedStringWithOptions: 0],
                                          }
                             bodyData: bodyData
                             delegate: self
                                  tag: worfc2_gameCenterVerifyConnection
                             userInfo: nil];
}

在服务器端:

从这个问题和其他问题,以及 php 文档和...

    $publicKeyURL = filter_var($headers['Publickeyurl'], FILTER_SANITIZE_URL);
    $pkURL = urlencode($publicKeyURL);
    if (empty($pkURL))
    {
        $response->addparameters(array('msg' => "no pku"));
        $response->addparameters(array("DEBUG-headers" => $headers));
        $response->addparameters(array('DEBUG-publicKeyURL' => $publicKeyURL));
        $response->addparameters(array('DEBUG-pkURL' => $pkURL));
        $response->setStatusCode(400);              // bad request
    }
    else
    {
        $sslCertificate = file_get_contents($publicKeyURL);
        if ($sslCertificate === false)
        {
            // invalid read
            $response->addparameters(array('msg' => "no certificate"));
            $response->setStatusCode(400);                  // bad request
        }
        else
        {
            // Example code from http://php.net/manual/en/function.openssl-verify.php
            try
            {
                // According to: http://stackoverflow.com/questions/10944071/parsing-x509-certificate
                $pemData = der2pem($sslCertificate);

                // fetch public key from certificate and ready it                    
                $pubkeyid = openssl_pkey_get_public($pemData);
                if ($pubkeyid === false)
                {
                    $response->addparameters(array('msg' => "public key error"));
                    $response->setStatusCode(400);              // bad request
                }
                else
                {
                    // According to: http://stackoverflow.com/questions/24621839/how-to-authenticate-the-gklocalplayer-on-my-third-party-server-using-php
                    // .. we use differently-formatted parameters
                    $sIOSData   = $body['data'];
                    $sIOSData   = base64_decode($sIOSData);
                    $sSignature = $headers['Signature'];
                    $sSignature = base64_decode($sSignature);

                    //$iResult = openssl_verify($sIOSData, $sSignature, $sKey, OPENSSL_ALGO_SHA1);

                    $dataToUse = $sIOSData;
                    $signatureToUse = $sSignature;

                    // state whether signature is okay or not
                    $ok = openssl_verify($dataToUse, $signatureToUse, $pubkeyid, OPENSSL_ALGO_SHA256);
                    if ($ok == 1)
                    {
                        //* echo "good";
                        $response->addparameters(array('msg' => "user validated"));
                    }
                    elseif ($ok == 0)
                    {
                        //* echo "bad";
                        $response->addparameters(array('msg' => "INVALID USER SIGNATURE"));
                        $response->addparameters(array("DEBUG-$dataToUse" => $dataToUse));
                        $response->addparameters(array("DEBUG-$signatureToUse" => $signatureToUse));
                        $response->addparameters(array("DEBUG-body" => $body));
                        $response->setStatusCode(401);                  // unauthorized
                    }
                    else
                    {
                        //* echo "ugly, error checking signature";
                        $response->addparameters(array('msg' => "***** ERROR checking signature"));
                        $response->setStatusCode(500);                  // server error
                    }

                    // free the key from memory
                    openssl_free_key($pubkeyid);
                }
            }
            catch (Exception $ex)
            {
                $response->addparameters(array('msg' => "verification error"));
                $response->addparameters(array("DEBUG-headers" => $headers));
                $response->addparameters(array('DEBUG-Exception' => $ex));
                $response->setStatusCode(400);              // bad request
            }
        }

        // NODE.js code at http://stackoverflow.com/questions/21570700/how-to-authenticate-game-center-user-from-3rd-party-node-js-server
    }

不要忘记方便的实用程序:

function der2pem($der_data)
{
   $pem = chunk_split(base64_encode($der_data), 64, "
");
   $pem = "-----BEGIN CERTIFICATE-----
" . $pem . "-----END CERTIFICATE-----
";
   return $pem;
}

使用所有这些,我终于能够从我的服务器获取用户验证".耶!:)

Using all of this, I was finally able to get "user validated" back from my server. Yay! :)

注意:这种方法似乎对黑客很开放,因为任何人都可以用自己的证书签署他们想要的任何东西,然后将数据、签名和 URL 传递给服务器到他们的证书,并得到一个那是一个有效的 GameCenter 登录"回答,虽然这段代码在实现 GC 算法的意义上有效",但算法本身似乎有缺陷.理想情况下,我们还会检查证书是否来自受信任的来源.检查它是否是 Apple 的 Game Center 证书的额外偏执也很好.

NOTE: This method seems very open to hacking, as anyone could sign whatever they want with their own certificate then pass the server the data, signature and URL to their certificate and get back a "that's a valid GameCenter login" answer so, while this code "works" in the sense that it implements the GC algorithm, the algorithm itself seems flawed. Ideally, we would also check that the certificate came from a trusted source. Extra-paranoia to check that it is Apple's Game Center certificate would be good, too.

这篇关于如何使用 PHP 在我的“第三方服务器"上验证 GKLocalPlayer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆