7

我正在寻找一种技术来从添加到 Opportunity 对象的自定义按钮执行 Apex 代码,以保护用户免受 CSRF 侵害​​。

当前使用的方法来自问题 -自定义按钮或使用自定义控制器链接到 Visualforce 页面。本质上:

  1. 有一个机会自定义按钮,内容源设置为“Visualforce 页面”。
  2. 此按钮的内容设置为 Visualforce 页面,该页面使用标准控制器的机会,输入了扩展 apex 类和该类中方法的操作
  3. 操作方法将 PageReference 返回到另一个自定义 Visualforce 页面,包括添加带有商机 ID 的参数。
  4. 第二个自定义 Visualforce 页面完成大部分实际工作,包括在将用户重定向回商机之前进行 Web 服务标注和执行 DML 操作。

这种方法的问题在于,第二个自定义 Visualforce 页面是通过 HTTP GET 检索的,从查询字符串中提取参数,并在没有 CSRF 保护的情况下执行更新/插入 DML 操作。Force.com 安全源代码扫描程序正在获取此信息。

我应该补充一点,此顶点代码同时部署为托管和非托管包,因此使用 PageReference 重定向到目标 Visualforce 页面的额外工作。这可确保在需要时添加命名空间前缀。

如何避免 CSRF 问题?

我不想在第二个visualforce页面中添加一个表单,他们必须按下一个按钮来启动进程(因此在回发中获取ViewStateCSRF保护)。从用户的角度来看,他们已经按下按钮来执行操作。

我之前在开发人员论坛上问过这个问题,但没有提出解决方案 - Cross-Site Request Forgery (CSRF/XSRF) safe Custom Button action

也许我应该尝试将代码从第二个视觉力页面的控制器中移出,并改为使用支架控制器的扩展?

我可以切换到 Apex Web 服务的 Javascript 回调(如Call a apex method from a custom buttonHow invoke APEX method from custom button中所建议的那样),但它看起来有点乱,我不确定我是否会只是打开了 Web 服务的另一个范围的安全问题。

4

2 回答 2

3

我通过 Salesforce 预订了合作伙伴安全办公时间,并直接与他们讨论了这个问题。

如果需要 CSRF 保护(即发布到 App Exchange),目前不支持我正在尝试做的事情。他们提出了两种替代方法:

  1. 在触发敏感 Apex 代码的 Visualforce 页面中创建中间表单。因此选择了内置的 CSRF 保护。
  2. 覆盖 Opportunity Detail 页面(使用 apex:Details 显示类似信息)。这个新的 Visualforce 页面将包含一个类似的表单回发到选项 1,以调用敏感的 APEX 代码并获得自动 CSRF 保护。

不使用自定义按钮的另一种方法是嵌入/内联 Visualforce 页面(请参阅在标准布局上嵌入页面),其中仅包含标准页面布局中所需的按钮。

嵌入的 Visualforce 页面必须使用标准对象控制器(在我的例子中为 Opportunity)才能出现在标准页面布局的可用 Visualforce 页面列表中。Visualforce 页面本身可以非常小,仅在<apex:form>. Visualforce 页面的标签也可以显示在页面布局中。

<apex:page id="embeddedPage" StandardController="Opportunity" extensions="OpportunityExtensionController" showHeader="false" standardStylesheets="true">
<apex:form >
    <apex:commandButton value="CSRF Safe Button" action="someMethodInTheExtensionClass" />
</apex:form>

public with sharing class OpportunityExtensionController {

    private final Opportunity opportunityFromController;

    public OpportunityExtensionController(ApexPages.StandardController controller) {
        opportunityFromController = (Opportunity)controller.getRecord();        
    }

    public PageReference someMethodInTheExtensionClass() {

        // Perform directly here within the postback rather than redirecting to another page to prevent against XSRF

        System.debug('opportunityFromController.Id:' + opportunityFromController.Id);
    }
}

这应该可以防止 CSRF,因为 commandButton 将拾取“com.salesforce.visualforce.ViewStateCSRF”隐藏输入,并在生成的 iframe 内将帖子发回服务器。


我已经从具有 CSRF 保护的标准实体详细信息页面中提出了 Idea Invoking Apex 代码,以查看他们是否可以使用自定义按钮直接添加对此的支持。

于 2012-06-12T22:55:19.843 回答
0

为什么不首先使用 JavaScript 按钮来启动第二个页面?完全绕过第一页。

Salesforce 将在呈现之前将合并应用到脚本(因此您可以使用{!Opportunity.Id}在第二个 URL 中包含 opp id)并且您可以简单地将浏览器重定向到您的第二个页面。

于 2012-05-31T08:07:32.210 回答