2013-03-14 70 views
5

我试图设置一个Sign in with Google按钮,该按钮允许用户在我的网站上购买物品。在客户端登录后对服务器端的G +用户进行身份验证

客户端认证看起来非常简单,但我很努力地理解服务器端认证是如何工作的。在example code中,它们将客户端“代码”参数传递给服务器,在该服务器中可以交换访问令牌,然后可以使用该令牌查看用户朋友的列表。

但我不想看到用户的朋友列表。我只想确定客户实际上是他们自称的客户。

取回令牌后,示例代码将该令牌放入会话中,似乎使用该令牌的存在来验证用户是否已通过身份验证。这是正确的/安全的吗?应该(不)我的服务器以何种方式重新验证令牌(如何?)何时需要购买?我是否应该每次向Google重新验证令牌? (希望不是?)

+0

我发布了一个相关的问题,因为我认为使用Facebook API执行此操作的标准方法是使用signed_request参数,但Google似乎没有相应的参数。 http://stackoverflow.com/questions/15395142/does-google-javascript-api-have-an-equivalent-to-facebooks-signed-request – 2013-03-14 16:57:42

回答

2

在执行购买之前,您可能想要做的是通过将用户标识从客户端安全地传递到服务器并根据用户标识进行验证来验证用户是否您期望他们是谁为存储的凭据。这为攻击者通过劫持他们的会话假装成为您的网站用户并在接受用户付款之前进行的最重要的检查提供了额外的防范重播攻击。

我不会仅依靠用户验证作为防范欺诈的机制。您应该使用安全支付系统,如Google Commerce platform,并按照the best practices for commerce

提醒一下,每次缓存的凭据初始化时,都应该使用OAuth2 v2端点来检查您的令牌。检查每个请求似乎有点过分,因为您应该使用已经验证并存储在服务器端的缓存凭据。在更新访问令牌时,至多可以执行检查,但如果您信任刷新令牌,则在创建帐户并设置刷新令牌时执行检查时应该足够安全。

以下步骤都采取了在除了用户ID验证建立帐户时:

  • 验证客户端是你希望它是谁。这可以防止伪造的访问令牌被传递到您的应用,以便代表攻击者使用您的配额有效发出请求。
  • 确认该帐户是由您的应用程序创建的,该帐户是在代表用户创建其他帐户的情况下创建的。

正如您的链接帖子中所提到的,the Google+ quickstarts中的示例代码应该充分说明如何使用多种编程语言对帐户授权执行这些检查。

中的HTML/JS客户端,下面的代码示出了用户ID(值,而不是特殊的字符串“我”),以传递给连接方法来验证的Google+ userID是检索到:

var request = gapi.client.plus.people.get({'userId' : 'me'}); 
    request.execute(function(profile) { 
     $('#profile').empty(); 
     if (profile.error) { 
     $('#profile').append(profile.error); 
     return; 
     } 
     helper.connectServer(profile.id); 
     $('#profile').append(
      $('<p><img src=\"' + profile.image.url + '\"></p>')); 
     $('#profile').append(
      $('<p>Hello ' + profile.displayName + '!<br />Tagline: ' + 
      profile.tagline + '<br />About: ' + profile.aboutMe + '</p>')); 
     if (profile.cover && profile.coverPhoto) { 
     $('#profile').append(
      $('<p><img src=\"' + profile.cover.coverPhoto.url + '\"></p>')); 
     } 
    }); 

...以下代码显示正在传送的Google+ ID。

connectServer: function(gplusId) { 
    console.log(this.authResult.code); 
    $.ajax({ 
    type: 'POST', 
    url: window.location.href + '/connect?state={{ STATE }}&gplus_id=' + 
     gplusId, 
    contentType: 'application/octet-stream; charset=utf-8', 
    success: function(result) { 
     console.log(result); 
     helper.people(); 
    }, 
    processData: false, 
    data: this.authResult.code 
    }); 
} 

在Java样品中执行这些检查相关的代码如下:

 // Check that the token is valid. 
     Oauth2 oauth2 = new Oauth2.Builder(
      TRANSPORT, JSON_FACTORY, credential).build(); 
     Tokeninfo tokenInfo = oauth2.tokeninfo() 
      .setAccessToken(credential.getAccessToken()).execute(); 
     // If there was an error in the token info, abort. 
     if (tokenInfo.containsKey("error")) { 
     response.status(401); 
     return GSON.toJson(tokenInfo.get("error").toString()); 
     } 
     // Make sure the token we got is for the intended user. 
     if (!tokenInfo.getUserId().equals(gPlusId)) { 
     response.status(401); 
     return GSON.toJson("Token's user ID doesn't match given user ID."); 
     } 
     // Make sure the token we got is for our app. 
     if (!tokenInfo.getIssuedTo().equals(CLIENT_ID)) { 
     response.status(401); 
     return GSON.toJson("Token's client ID does not match app's."); 
     } 
     // Store the token in the session for later use. 
     request.session().attribute("token", tokenResponse.toString()); 
     return GSON.toJson("Successfully connected user."); 
    } catch (TokenResponseException e) { 
     response.status(500); 
     return GSON.toJson("Failed to upgrade the authorization code."); 
    } catch (IOException e) { 
     response.status(500); 
     return GSON.toJson("Failed to read token data from Google. " + 
      e.getMessage()); 
    } 

在该样品中ClientID的从谷歌API控制台来了,将是不同的应用程序。

+0

1)“传递用户ID”你的意思是“代码”参数?或用户ID? 2)“根据存储的凭证进行验证”示例代码不存储凭证。究竟应该存储什么?多长时间? (数据库?会话?)更具哲理意义的是,代码示例似乎没有按照您的建议做。他们呢? (比如说)Java样本的哪些行可以完成你所说的内容? – 2013-03-16 00:32:07

+0

1)在样本的HTML/JS客户端(index.html)的连接方法中,您会注意到Google+ ID作为GET参数传递并使用令牌信息进行验证。 2)样本*模拟*使用会话存储来存储用户凭证的操作,并使用存储的访问/刷新令牌重新创建授权状态。刷新标记不会过期,因此应该安全地保留,除非用户断开其帐户。访问令牌在3600秒后过期,因此应仅在过期时更新。第153-183行正在Java样本中执行检查。 – class 2013-03-17 08:15:12

+0

最后一个评论,如果你想看到一个更全面的例子,应该如何保存令牌和凭证,PhotoHunt样本将更好地证明这一点。在这里查看saveTokenForUser:https://github.com/googleplus/gplus-photohunt-server-java/blob/master/src/com/google/plus/samples/photohunt/ConnectServlet.java – class 2013-03-17 08:22:55

相关问题