是否足以从服务器请求一个 XSRF令牌并在整个会话中重复使用或我是否应该请求保存,编辑或保存等每项保护措施首先删除新 XSRF令牌然后然后执行实际请求?
出现这个问题是因为我不明白为什么我的XSRF保护请求正在运行,即使我没有请求新请求:
public void saveName(Long shopId, Long languageId, String name, OnSuccessCallback<String> success, OnFailureCallback failure) {
Request.<String> doRequest(this.shopService,
asyncCallback -> {
this.shopService.saveName(shopId, languageId, name, asyncCallback);
},
(String result) -> {
// ..
success.onSuccess(result);
}, failure);
}
此处Request#doRequest()
只会执行请求,但不会首先要求新的XSRF令牌。我必须将其更改为XsrfRequest#doRequest()
,它基本上会做同样的事情,但会首先请求 XSRF令牌。
事情是saveName()
应该受到保护:
@XsrfProtect
@RemoteServiceRelativePath("shop")
public interface ShopServlet extends RemoteService {
// ..
String saveName(Long shopId, Long languageId, String name);
}
请注意:在saveName()
被调用之前,还有其他一些请求,其中一些已经获得了XSRF令牌。但是因为我可以在不请求新名称的情况下保存新名称,所以我觉得以前请求的令牌在这里被重用了。这样可以吗?
我注意到的另一件事是我将@NoXsrfProtect
添加到saveName()
@NoXsrfProtect
String saveName(Long restaurantId, Long languageId, String name);
请求仍将包含XSRF令牌信息:
7|2|9|http://localhost:8080/app/|424F33664CAA93E2F8A4A94C57DA5827|com.google.gwt.user.client.rpc.XsrfToken/4254043109|..ShopServlet|saveName|java.lang..
为什么令牌被发送到这里,即使该方法被声明为@NoXsrfProtect
?
有人可以向我澄清一下吗?我不想犯任何错误 - 特别是在与安全有关的事情上......
答案 0 :(得分:0)
是否足以从服务器请求一个XSRF令牌并在整个会话中重复使用它,或者我是否应该首先请求保存,编辑或删除新的XSRF令牌等每个有保护的操作,然后执行实际请求?< / p>
让我们暂时忽略GWT RPC的内置XSRF保护并查看标题问题和这句话:什么是XSRF以及我们如何防范它?
GET /transfer?from=me&to=attacker&amount=10000USD
然后,攻击者可以非常简单地从他们自己的站点向我们的服务器发出请求,作为图像,css或js文件:
<img src="https://securebank.com/transfer?from=me&to=attacker&amount=10000USD" />
撇开其他细节(“好吧,这适用于GET,他们是如何设法将POST发送到我的GWT RPC服务的?”),让我们看看XSRF“令牌”防止这种攻击的想法:什么是一个友好的客户知道或可以做,攻击者无法知道或做什么?
这个想法是客户端应该有一种方法向服务器指示它是可信的 - 它知道只有有效的客户端可以知道的东西,这表明用户愿意做出指定的动作。一种选择是要求用户执行验证码,使得攻击站点无法编写操作脚本,并且用户必须有意识地执行。另一种选择是将一些数据提供给真实/可信客户端,例如cookie(只能从加载在同一域中的页面读取),或者作为HTML页面加载时的一部分或其他一些请求(也许可以通过其他方式发送,但结果无法读取。)
OWASP将后一段数据称为"Synchronizer Token":
同步器令牌模式需要生成与用户当前会话关联的随机“质询”令牌。 [...]当用户希望调用这些敏感操作时,HTTP请求应包含此质询令牌。然后,服务器应用程序负责验证此令牌的存在性和正确性。
因此,在这种情况下,我们可以为cookie写一些值,以便只有客户端可以看到它,然后客户端可以使用它来生成令牌。然后,应该在每个必须验证的请求上将该令牌传递给服务器。但是从这个描述中,我们发现一次只有一个有效令牌并不一定很重要。
这是真的,但如果他们有一个XSS,那么你自己的JS可以做出的任何请求,攻击也可以。你迷路了,打包店,回家的时间。同样,如果他们拥有用户和应用程序之间的连接,并可以随意读写。 XSRF保护不是解决所有问题的魔杖,它是一种特定的攻击,只需要自己解决:如果窗口可能被破坏,家中的锁定不会被视为错误。
那么GWT如何做到这一点?如您所述,@XsrfProtect
注释将服务类型标记为需要在服务器上进行检查。然后,客户端必须请求令牌,然后确保客户端的服务知道该令牌以用于将来的请求。
那么服务器如何生成令牌?服务器上的XsrfTokenServiceServlet
RPC服务生成令牌,作为每次调用服务器的一部分,如您所见,XsrfProtectedServiceServlet.validateXsrfToken
然后验证这是正确的。如果你想要自定义行为,你必须修改该系统的每一面,并且可以构建它以使每个令牌一旦使用就无效,但这不是默认的(也不是,根据OWASP,鼓励它。)
我注意到的另一件事是我将@NoXsrfProtect添加到saveName()......
请注意validateXsrfToken
只在GWT的一个地方调用,来自AbstractXsrfProtectedServiceServlet
:
@Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
if (shouldValidateXsrfToken(rpcRequest.getMethod())) {
validateXsrfToken(rpcRequest.getRpcToken(), rpcRequest.getMethod());
}
}
方法shouldValidateXsrfToken
然后检查方法是否明确禁用了保护。如果是这样,它将返回false,并且不会执行检查。但是在构建RPCRequest
对象时,RPC.decodeRequest
总是会附加令牌,即使该令牌恰好是null:
RpcToken rpcToken = null;
if (streamReader.hasFlags(AbstractSerializationStream.FLAG_RPC_TOKEN_INCLUDED)) {
// Read the RPC token
rpcToken = (RpcToken) streamReader.deserializeValue(RpcToken.class);
}
因此,如果客户端配置为发送令牌,它将始终发送,但服务器可能会忽略它。