Twitter OAuth dance使用GET进行身份验证,但Apex CSRF保护仅针对POST提供

时间:2012-02-01 19:47:50

标签: oauth twitter twitter-oauth apex-code visualforce

这是我想弄清楚的安全问题。 的所有内容都很好,我可以从我的托管软件包内部向AppExchange发送用户身份验证的用户。问题是Twitter OAuth 1.0进程(或“舞蹈”)有通信步骤,GET从Twitter返回到我的应用程序。虽然这有效,但根据安全测试通过online以及现在使用Eclipse中的CxViewer,安全审查过程是一个危险信号。

但我需要从Twitter获取此信息并以某种方式为每个用户存储 。这个问题的示例代码入口点,其中Twitter从我的一个auth_token请求回调,将是:

页:

<apex:page controller="AuthController" action="{!completeAuthorization}"/>

顶点:

public PageReference completeAuthorization() 
{
   String token = ApexPages.currentPage().getParameters().get('oauth_token');
   CustomObject__c c = new CustomObject__c(Name = token);
   insert c; // <--- Security flaw here! (except that it's Twitter, not Trojan.com)
}

我已经阅读了有关该主题的所有提供的Apex文档,再次阅读,浏览论坛,不幸的是想出了zilch / nada。非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

这是我发现的。该问题涉及让GET参数指示有关在Salesforce中选择的对象的任何内容,然后将数据保存到该对象。我不相信有任何真正的安全问题,并且我的新代码安全测试通过没有问题。发生的事情基本上是这样的:

String token = ApexPages.currentPage().getParameters().get('oauth_token');

CustomObject__c pcs = [
SELECT Id, User__c, Token__c 
FROM CustomObject__c 
WHERE Id = :UserInfo.getUserId() 
AND Token__c = :EncodingUtil.urlEncode(token, 'UTF-8'];

由于整个交换从我的上下文开始,在那里我100%肯定当前用户(UserInfo.getUserId()),我不需要检查此特定令牌是否匹配因为保证了用户(至少与我有关,因为它启动了这个过程)。所以以下选择工作正常:

CustomObject__c pcs = [
SELECT Id, User__c, Token__c 
FROM CustomObject__c 
WHERE Id = :UserInfo.getUserId()];

稍后如果我对此对象进行更新:

update pcs;

它没有抱怨,因为传入的GET值与为写入选择的对象没有任何连接。然而,正如您可能会注意到的那样,只要我包含

,就不会出现问题
WHERE Id = :UserInfo.getUserId()

到SOQL语句。原因是无论攻击试图向我的代码注入什么错误令牌,它仍然会针对当前用户进行验证,并且如果用户不匹配则无论如何都会失败。但是在Salesforce中,没有办法让两个同时用户同时登录,就像大多数系统一样,所以令牌检查从一开始就太过分了,因为我从不共享我的用户ID鸣叫声。

需要存储的 实际 令牌(oauth_token和oauth_secret)可以作为POST参数检索,因此具有内置的Salesforce CSRF保护。这些检索如下:

Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint(accessTokenURL);
req.setBody('');
sign(req);
HttpResponse res = new HttpResponse();
String resParams = res.getBody();
Map<String,String> rp = new Map<String,String>();

if(resParams != null)
{
   for(String s : resParams.split('&')) 
   {
      List<String> kv = s.split('=');
      rp.put(kv[0],kv[1]);
   }
}

tK.Secret__c = rp.get('oauth_token_secret');
tK.Token__c = rp.get('oauth_token');

upsert tK; // No problem, it's from a POST body

我准备发布奖金;)