在MVC应用程序中应在哪里生成CSRF表单令牌和CAPTCHA?

时间:2018-10-21 22:24:18

标签: php model-view-controller captcha csrf-token

给出:

我已经创建了HashCaptcha类。 Hash创建表单令牌。 Captcha使用Graphics类创建图像。自定义会话服务包装器类用于处理$_SESSION超全局数据结构。

场景:

我使用依赖项注入容器。因此,我想知道在哪里可以为公共可访问的HTML表单定义CaptchaHash的实例化。

假设1:您应将HashCaptcha注入Model的子级中,因为存储需要访问$_SESSION(基于HTTP)请求)并验证(根据HTTP响应)CSRF令牌和CAPTCHA答案。视图从不应该访问会话数据结构。

假设2:您应该将HashCaptcha注入View的子级中,因为生成CSRF令牌和验证码实际上是View的表示逻辑,即使它们在Model中进行了验证。允许从View直接或间接访问会话数据结构。

假设一似乎是答案,但我想确定。

摘要示例:

$session = new Session(); // A custom wrapper class
$hash = new Hash();
$graphics = new Graphics();
$captcha = new Captcha($graphics);


$model = new ContactModel($session, $hash, $captcha);

$view = new ContactView($session, $hash, $captcha);

2 个答案:

答案 0 :(得分:2)

  

注释#1::我认为您应该通读this post。我将强调此答案的核心部分:“模型不是类或任何单个对象”

     

注释#2: IMO,此问题是Web MVC实现所固有的。第一部分是我将如何解决这个问题;下面从概念上描述了为什么存在此问题。

我的答案是: 都不是

MVC体系结构分为两层:模型层和表示层。服务对象(位于模型层中)应实例化/将相关的验证码信息保存/保存到客户端状态。由于这可能是Web应用程序,因此表示层(特别是视图对象)将需要从模型层请求此客户端状态。这是通过服务对象还是专为客户端状态响应量身定制的特定于演示的数据访问对象而发生的,取决于您的实现方式和最佳配合。在此视图中,我将通过另一个数据访问对象或(Cookie/Session)Response抽象*将客户端状态保存到会话中。这样,视图就不会“访问”会话数据结构,而是利用组件(表示层DAO或(Cookie/Session)Response抽象*)来完成这项工作。尽管我们不认为cookie /会话是表示形式(“它们不是可视的” ),但是表示层负责响应,而cookie /会话则是其中的全部内容。

由于模型层似乎混为一谈,因此我很难推测出这在您的框架中将如何进行。您的ContactModel当然希望哈希/验证码保存客户端状态。您的视图既不需要这些,也不需要其他机制,以cookie /会话的形式将客户端状态“响应”到HTTP请求。

  

* Symfony通常对此有所帮助。我同时使用了表示层DAO和一个Symfony HttpFoundation对象,该对象可能太高了。

从概念上讲:会话是状态还是响应

您要在此处解决的基本问题特定于Web MVC实现。 Web MVC中的表示层处理一个“请求”(委托给控制器)​​并显示一个“响应”(由视图决定)。在HTTP中,cookie和会话与请求一起发送,并在响应中进行更改。这是嵌入在HTTP请求/响应性质中的。

如果将会话/ cookie保存放置在模型层中,那么我们将使模型层依赖于HTTP并允许其“响应”请求。即使我们抽象超全局变量并“注入”抽象(例如Symfony cookie /会话对象),也存在对cookie /会话(请求/响应实现)的内在依赖。您可以在模型层中全部完成操作,但我不愿意。换句话说,尽管模型负责跟踪状态,但cookie /会话状态实际上是对请求的响应。

“但这是漏逻辑,因为您要在表示层中保存状态”

我认为您可以将所有方法视为“漏泄”,这只是最有凝聚力的方法。如果您将cookie /会话视为状态,那么我们肯定会在表示层中“保存”状态。如果您将它们视为响应,而它们确实在MVC的眼中,那么这根本不是泄漏。我认为在模型层中发送响应(保存会话/ cookie状态)更糟。

答案 1 :(得分:0)

答案:您应该在“模型”中生成CSRF令牌和CAPTCHA值。

原因:这些值的目的是限制您的业务逻辑,而不仅仅是在“视图”中显示值或控件。如果“视图”生成了表单令牌和CAPTCHA质询值,则必须将它们传递回“模型”(一种或另一种方式)。这与流程相反。

尽管第二个假设是可行的,但它赋予“未完全完成”的观点以职责。具体来说,View绝不会负责验证表单令牌或验证码答案。

例如,View可以以虚拟方式将表单令牌和CAPTCHA挑战插入HTML表单模板中。的确如此,但是现在“视图”将负责将答案保存到某种持久性存储中,而“模型”将仅检索并验证它们。

因此,会话存储将像“视图”和“模型”之间的背面通道一样,因此将它们耦合(即使使用某种会话服务包装器)。 “视图” 不应传递数据作为“模型”,但这实际上是如果允许“视图”生成表单令牌和CAPTCHA答案值的情况。

这是我的答案。我欢迎您的评论和批评。