Salesforce 链接到Apex方法的CSRF安全自定义按钮
我正在寻找一种技术,从添加到Opportunity对象的自定义按钮执行Apex代码,以保护用户免受CSRF的影响 当前使用的方法来自于问题-。基本上:Salesforce 链接到Apex方法的CSRF安全自定义按钮,salesforce,csrf,apex-code,visualforce,Salesforce,Csrf,Apex Code,Visualforce,我正在寻找一种技术,从添加到Opportunity对象的自定义按钮执行Apex代码,以保护用户免受CSRF的影响 当前使用的方法来自于问题-。基本上: 有一个Opportunity自定义按钮,其内容源设置为“Visualforce页面” 此按钮的内容设置为Visualforce页面,该页面使用standardController的Opportunity,并输入了扩展apex类和该类中方法的操作 action方法返回对另一个自定义Visualforce页面的PageReference,包括添加带有
我可以切换到Apex Web服务的Javascript回调(如和中所建议的),但它似乎有点混乱,我不确定是否会打开Web服务的另一系列安全问题。为什么不首先使用Javascript按钮启动第二个页面?完全绕过第一页
Salesforce将在呈现之前对脚本应用合并(因此您可以使用
{!Opportunity.Id}
在第二个URL中包含opp Id),您只需将浏览器重定向到第二个页面即可。我与Salesforce预约了合作伙伴安全办公时间,并直接与他们讨论了此问题
如果需要CSRF保护(即发布到应用程序交换),则当前不支持我尝试执行的操作。他们提出了两种备选办法:
另一种不使用自定义按钮的方法是嵌入/内联Visualforce页面(请参见仅在标准页面布局中包含所需按钮)
嵌入式Visualforce页面必须使用标准对象控制器(在我的例子中是Opportunity)出现在标准页面布局上的可用Visualforce页面列表中。Visualforce页面本身可以非常小,只需
中的一个commandButton,就可以查看他们是否可以通过自定义按钮直接添加对此的支持。我遇到的主要问题是,当用户通过HTTP GET请求到达第二个页面时,他们是向CSRF打开,因为第二个页面将接受查询字符串参数,并执行插入和更新操作以及Web服务调用。此外,使用Javascript,由于名称空间前缀的原因,我无法以在托管包内部和外部工作的方式引用目标visualforce页面。好的,#1您可以使用URLFOR
或>$Page.pagename
或它们的组合来引用页面。这应该会解决您的命名空间问题。其次,CSRF应该只针对表单操作启动,我的理解是,您在第2页中没有这样的东西,不是吗?基本上是您的扩展构造函数完成了所有工作?如果是这样,您的页面将仍然对CSRF开放,无论发生什么,您都无法解决在salesforce呈现表单(带有令牌)并从加载提交表单时,您不需要使用此方法来解决CSRF问题(参见下一条注释)您无法解决此问题,因为知道您的页面的恶意网站仍然可以发送带有查询字符串的GET请求,并让salesforce为其创建一个令牌并为其提交。感谢您坚持此操作。关于使用Javascript,当我以前尝试在自定义按钮中使用带有$page.pagename的URLFOR时[我有一个错误]()。也许我应该重新考虑这个问题,因为它现在可以工作了?不幸的是,任何不依赖salesforce呈现表单并由用户发回表单的解决方案都对CSRF开放。您只会使安全漏洞更“奇特”,但您不会删除它。抱歉。
<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);
}
}